Mercurial > hg > nginx
comparison src/event/ngx_event_quic.c @ 8199:1297dc83a6b9 quic
Generic payload handler for quic packets.
- added basic parsing of ACK, PING and PADDING frames on input
- added preliminary parsing of SHORT headers
The ngx_quic_output() is now called after processing of each input packet.
Frames are added into output queue according to their level: inital packets
go ahead of handshake and application data, so they can be merged properly.
The payload handler is called from both new, handshake and applicataion data
handlers (latter is a stub).
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Tue, 10 Mar 2020 18:24:39 +0300 |
parents | ff14b0fe9731 |
children | 9582adbc7d70 |
comparison
equal
deleted
inserted
replaced
8198:ff14b0fe9731 | 8199:1297dc83a6b9 |
---|---|
132 typedef enum ssl_encryption_level_t ngx_quic_level_t; | 132 typedef enum ssl_encryption_level_t ngx_quic_level_t; |
133 | 133 |
134 typedef struct ngx_quic_frame_s ngx_quic_frame_t; | 134 typedef struct ngx_quic_frame_s ngx_quic_frame_t; |
135 | 135 |
136 typedef struct { | 136 typedef struct { |
137 ngx_uint_t pn; | 137 ngx_uint_t pn; |
138 // ngx_uint_t nranges; | 138 |
139 // ... | 139 // input |
140 uint64_t largest; | |
141 uint64_t delay; | |
142 uint64_t range_count; | |
143 uint64_t first_range; | |
144 uint64_t ranges[20]; | |
145 /* ecn counts */ | |
140 } ngx_quic_ack_frame_t; | 146 } ngx_quic_ack_frame_t; |
141 | 147 |
142 typedef ngx_str_t ngx_quic_crypto_frame_t; | 148 typedef struct { |
149 size_t offset; | |
150 size_t len; | |
151 u_char *data; | |
152 } ngx_quic_crypto_frame_t; | |
153 | |
143 | 154 |
144 struct ngx_quic_frame_s { | 155 struct ngx_quic_frame_s { |
145 ngx_uint_t type; | 156 ngx_uint_t type; |
146 ngx_quic_level_t level; | 157 ngx_quic_level_t level; |
147 ngx_quic_frame_t *next; | 158 ngx_quic_frame_t *next; |
205 | 216 |
206 | 217 |
207 static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, | 218 static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, |
208 ngx_buf_t *b); | 219 ngx_buf_t *b); |
209 static ngx_int_t ngx_quic_handshake_input(ngx_connection_t *c, ngx_buf_t *b); | 220 static ngx_int_t ngx_quic_handshake_input(ngx_connection_t *c, ngx_buf_t *b); |
221 static ngx_int_t ngx_quic_app_input(ngx_connection_t *c, ngx_buf_t *b); | |
210 | 222 |
211 static int ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn, | 223 static int ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn, |
212 enum ssl_encryption_level_t level, const uint8_t *read_secret, | 224 enum ssl_encryption_level_t level, const uint8_t *read_secret, |
213 const uint8_t *write_secret, size_t secret_len); | 225 const uint8_t *write_secret, size_t secret_len); |
214 static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, | 226 static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, |
223 static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, | 235 static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, |
224 enum ssl_encryption_level_t level, uint8_t alert); | 236 enum ssl_encryption_level_t level, uint8_t alert); |
225 | 237 |
226 static ngx_int_t ngx_quic_process_long_header(ngx_connection_t *c, | 238 static ngx_int_t ngx_quic_process_long_header(ngx_connection_t *c, |
227 ngx_quic_header_t *pkt); | 239 ngx_quic_header_t *pkt); |
240 static ngx_int_t ngx_quic_process_short_header(ngx_connection_t *c, | |
241 ngx_quic_header_t *pkt); | |
228 static ngx_int_t ngx_quic_process_initial_header(ngx_connection_t *c, | 242 static ngx_int_t ngx_quic_process_initial_header(ngx_connection_t *c, |
229 ngx_quic_header_t *pkt); | 243 ngx_quic_header_t *pkt); |
230 static ngx_int_t ngx_quic_process_handshake_header(ngx_connection_t *c, | 244 static ngx_int_t ngx_quic_process_handshake_header(ngx_connection_t *c, |
231 ngx_quic_header_t *pkt); | 245 ngx_quic_header_t *pkt); |
232 static ngx_int_t ngx_quic_initial_secret(ngx_connection_t *c); | 246 static ngx_int_t ngx_quic_initial_secret(ngx_connection_t *c); |
274 | 288 |
275 ngx_int_t | 289 ngx_int_t |
276 ngx_quic_input(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b) | 290 ngx_quic_input(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b) |
277 { | 291 { |
278 if (c->quic == NULL) { | 292 if (c->quic == NULL) { |
279 return ngx_quic_new_connection(c, ssl, b); //TODO: change state by results | 293 return ngx_quic_new_connection(c, ssl, b); |
280 } | 294 } |
281 | 295 |
282 switch (c->quic->state) { | 296 if (b->start[0] & NGX_QUIC_PKT_LONG) { |
283 case NGX_QUIC_ST_INITIAL: | 297 // TODO: check current state |
284 case NGX_QUIC_ST_HANDSHAKE: | |
285 return ngx_quic_handshake_input(c, b); | 298 return ngx_quic_handshake_input(c, b); |
286 default: | 299 } |
287 /* application data */ | 300 |
288 break; | 301 return ngx_quic_app_input(c, b); |
289 } | |
290 | |
291 return NGX_OK; | |
292 } | 302 } |
293 | 303 |
294 static ngx_int_t | 304 static ngx_int_t |
295 ngx_quic_send_packet(ngx_connection_t *c, ngx_quic_connection_t *qc, | 305 ngx_quic_send_packet(ngx_connection_t *c, ngx_quic_connection_t *qc, |
296 ngx_quic_level_t level, ngx_str_t *payload) | 306 ngx_quic_level_t level, ngx_str_t *payload) |
377 } | 387 } |
378 | 388 |
379 start = p; | 389 start = p; |
380 | 390 |
381 ngx_quic_build_int(&p, NGX_QUIC_FT_CRYPTO); | 391 ngx_quic_build_int(&p, NGX_QUIC_FT_CRYPTO); |
382 ngx_quic_build_int(&p, 0); | 392 ngx_quic_build_int(&p, crypto->offset); |
383 ngx_quic_build_int(&p, crypto->len); | 393 ngx_quic_build_int(&p, crypto->len); |
384 p = ngx_cpymem(p, crypto->data, crypto->len); | 394 p = ngx_cpymem(p, crypto->data, crypto->len); |
385 | 395 |
386 return p - start; | 396 return p - start; |
387 } | 397 } |
450 return NGX_ERROR; | 460 return NGX_ERROR; |
451 } | 461 } |
452 | 462 |
453 return NGX_OK; | 463 return NGX_OK; |
454 } | 464 } |
465 | |
455 | 466 |
456 ngx_int_t | 467 ngx_int_t |
457 ngx_quic_output(ngx_connection_t *c) | 468 ngx_quic_output(ngx_connection_t *c) |
458 { | 469 { |
459 size_t len; | 470 size_t len; |
800 if (qc->frames == NULL) { | 811 if (qc->frames == NULL) { |
801 qc->frames = frame; | 812 qc->frames = frame; |
802 return; | 813 return; |
803 } | 814 } |
804 | 815 |
805 for (f = qc->frames; f->next; f = f->next) { /* void */ } | 816 for (f = qc->frames; f->next; f = f->next) { |
806 | 817 if (f->next->level > frame->level) { |
818 break; | |
819 } | |
820 } | |
821 | |
822 frame->next = f->next; | |
807 f->next = frame; | 823 f->next = frame; |
808 } | 824 } |
809 | 825 |
810 | 826 |
811 static int | 827 static int |
842 | 858 |
843 ngx_sprintf(frame->info, "crypto, generated by SSL len=%ui level=%d", len, level); | 859 ngx_sprintf(frame->info, "crypto, generated by SSL len=%ui level=%d", len, level); |
844 | 860 |
845 ngx_quic_queue_frame(qc, frame); | 861 ngx_quic_queue_frame(qc, frame); |
846 | 862 |
847 if (level == ssl_encryption_initial) { | |
848 frame = ngx_pcalloc(c->pool, sizeof(ngx_quic_frame_t)); | |
849 if (frame == NULL) { | |
850 return 0; | |
851 } | |
852 frame->level = level; | |
853 frame->type = NGX_QUIC_FT_ACK; | |
854 frame->u.ack.pn = 0; | |
855 ngx_sprintf(frame->info, "ACK for PN=0 at initial, added manually from add_handshake_data"); | |
856 | |
857 ngx_quic_queue_frame(qc, frame); | |
858 } | |
859 | |
860 return 1; | 863 return 1; |
861 } | 864 } |
862 | 865 |
863 | 866 |
864 static int | 867 static int |
867 ngx_connection_t *c; | 870 ngx_connection_t *c; |
868 | 871 |
869 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | 872 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); |
870 | 873 |
871 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "ngx_quic_flush_flight()"); | 874 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "ngx_quic_flush_flight()"); |
872 | |
873 if (ngx_quic_output(c) != NGX_OK) { | |
874 return 0; | |
875 } | |
876 | 875 |
877 return 1; | 876 return 1; |
878 } | 877 } |
879 | 878 |
880 | 879 |
889 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 888 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
890 "ngx_quic_send_alert(), lvl=%d, alert=%d", | 889 "ngx_quic_send_alert(), lvl=%d, alert=%d", |
891 (int) level, (int) alert); | 890 (int) level, (int) alert); |
892 | 891 |
893 return 1; | 892 return 1; |
893 } | |
894 | |
895 | |
896 /* TODO: stub for short packet header processing */ | |
897 static ngx_int_t | |
898 ngx_quic_process_short_header(ngx_connection_t *c, ngx_quic_header_t *pkt) | |
899 { | |
900 u_char *p; | |
901 | |
902 p = pkt->buf.data; | |
903 | |
904 ngx_quic_hexdump0(c->log, "input", pkt->buf.data, pkt->buf.len); | |
905 | |
906 if ((p[0] & NGX_QUIC_PKT_LONG)) { | |
907 ngx_log_error(NGX_LOG_INFO, c->log, 0, "not a short packet"); | |
908 return NGX_ERROR; | |
909 } | |
910 | |
911 pkt->flags = *p++; | |
912 | |
913 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
914 "quic flags:%xi", pkt->flags); | |
915 | |
916 if (ngx_memcmp(p, c->quic->dcid.data, c->quic->dcid.len) != 0) { | |
917 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcid"); | |
918 return NGX_ERROR; | |
919 } | |
920 | |
921 pkt->dcid.data = p; | |
922 p += c->quic->dcid.len; | |
923 | |
924 pkt->pos = p; | |
925 | |
926 return NGX_OK; | |
894 } | 927 } |
895 | 928 |
896 | 929 |
897 static ngx_int_t | 930 static ngx_int_t |
898 ngx_quic_process_long_header(ngx_connection_t *c, ngx_quic_header_t *pkt) | 931 ngx_quic_process_long_header(ngx_connection_t *c, ngx_quic_header_t *pkt) |
1158 | 1191 |
1159 if (ngx_quic_tls_hp(c, hp, pkt->secret, mask, sample) != NGX_OK) { | 1192 if (ngx_quic_tls_hp(c, hp, pkt->secret, mask, sample) != NGX_OK) { |
1160 return NGX_ERROR; | 1193 return NGX_ERROR; |
1161 } | 1194 } |
1162 | 1195 |
1163 clearflags = pkt->flags ^ (mask[0] & 0x0f); | 1196 if (pkt->flags & NGX_QUIC_PKT_LONG) { |
1197 clearflags = pkt->flags ^ (mask[0] & 0x0f); | |
1198 | |
1199 } else { | |
1200 clearflags = pkt->flags ^ (mask[0] & 0x1f); | |
1201 } | |
1202 | |
1164 pnl = (clearflags & 0x03) + 1; | 1203 pnl = (clearflags & 0x03) + 1; |
1165 pn = ngx_quic_parse_pn(&p, pnl, &mask[1]); | 1204 pn = ngx_quic_parse_pn(&p, pnl, &mask[1]); |
1166 | 1205 |
1167 pkt->pn = pn; | 1206 pkt->pn = pn; |
1168 | 1207 |
1173 "quic packet number: %uL, len: %xi", pn, pnl); | 1212 "quic packet number: %uL, len: %xi", pn, pnl); |
1174 | 1213 |
1175 /* packet protection */ | 1214 /* packet protection */ |
1176 | 1215 |
1177 in.data = p; | 1216 in.data = p; |
1178 in.len = pkt->buf.len - pnl; | 1217 |
1179 | 1218 if (pkt->flags & NGX_QUIC_PKT_LONG) { |
1180 ad.len = p - pkt->buf.data;; | 1219 in.len = pkt->buf.len - pnl; |
1220 | |
1221 } else { | |
1222 in.len = pkt->buf.data + pkt->buf.len - p; | |
1223 } | |
1224 | |
1225 ad.len = p - pkt->buf.data; | |
1181 ad.data = ngx_pnalloc(c->pool, ad.len); | 1226 ad.data = ngx_pnalloc(c->pool, ad.len); |
1182 if (ad.data == NULL) { | 1227 if (ad.data == NULL) { |
1183 return NGX_ERROR; | 1228 return NGX_ERROR; |
1184 } | 1229 } |
1185 | 1230 |
1197 nonce, &in, &ad); | 1242 nonce, &in, &ad); |
1198 | 1243 |
1199 ngx_quic_hexdump0(c->log, "packet payload", | 1244 ngx_quic_hexdump0(c->log, "packet payload", |
1200 pkt->payload.data, pkt->payload.len); | 1245 pkt->payload.data, pkt->payload.len); |
1201 | 1246 |
1247 pkt->pos = pkt->payload.data; | |
1248 | |
1202 return rc; | 1249 return rc; |
1203 } | 1250 } |
1204 | 1251 |
1205 | 1252 |
1253 ngx_int_t | |
1254 ngx_quic_read_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, | |
1255 ngx_quic_frame_t *frame) | |
1256 { | |
1257 u_char *p, *end; | |
1258 | |
1259 size_t npad; | |
1260 | |
1261 p = pkt->pos; | |
1262 end = pkt->payload.data + pkt->payload.len; | |
1263 | |
1264 frame->type = *p++; | |
1265 | |
1266 switch (frame->type) { | |
1267 | |
1268 case NGX_QUIC_FT_CRYPTO: | |
1269 frame->u.crypto.offset = *p++; | |
1270 frame->u.crypto.len = ngx_quic_parse_int(&p); | |
1271 frame->u.crypto.data = p; | |
1272 p += frame->u.crypto.len; | |
1273 | |
1274 ngx_quic_hexdump0(c->log, "CRYPTO frame", | |
1275 frame->u.crypto.data, frame->u.crypto.len); | |
1276 | |
1277 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1278 "quic CRYPTO frame length: %uL off:%uL pp:%p", | |
1279 frame->u.crypto.len, frame->u.crypto.offset, | |
1280 frame->u.crypto.data); | |
1281 break; | |
1282 | |
1283 case NGX_QUIC_FT_PADDING: | |
1284 npad = 0; | |
1285 while (p < end && *p == NGX_QUIC_FT_PADDING) { // XXX | |
1286 p++; npad++; | |
1287 } | |
1288 | |
1289 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1290 "PADDING frame length %uL", npad); | |
1291 | |
1292 break; | |
1293 | |
1294 case NGX_QUIC_FT_ACK: | |
1295 case NGX_QUIC_FT_ACK_ECN: | |
1296 | |
1297 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "ACK frame"); | |
1298 | |
1299 frame->u.ack.largest = ngx_quic_parse_int(&p); | |
1300 frame->u.ack.delay = ngx_quic_parse_int(&p); | |
1301 frame->u.ack.range_count =ngx_quic_parse_int(&p); | |
1302 frame->u.ack.first_range =ngx_quic_parse_int(&p); | |
1303 | |
1304 if (frame->u.ack.range_count) { | |
1305 frame->u.ack.ranges[0] = ngx_quic_parse_int(&p); | |
1306 } | |
1307 | |
1308 if (frame->type ==NGX_QUIC_FT_ACK_ECN) { | |
1309 return NGX_ERROR; | |
1310 } | |
1311 | |
1312 break; | |
1313 | |
1314 case NGX_QUIC_FT_PING: | |
1315 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "PING frame"); | |
1316 p++; | |
1317 break; | |
1318 default: | |
1319 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1320 "unknown frame type %xi", frame->type); | |
1321 return NGX_ERROR; | |
1322 } | |
1323 | |
1324 pkt->pos = p; | |
1325 | |
1326 return NGX_OK; | |
1327 } | |
1328 | |
1329 | |
1206 static ngx_int_t | 1330 static ngx_int_t |
1207 ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b) | 1331 ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, |
1208 { | 1332 ngx_quic_frame_t *frame) |
1209 int n, sslerr; | 1333 { |
1210 ngx_str_t out; | 1334 int sslerr; |
1211 ngx_quic_connection_t *qc; | 1335 ssize_t n; |
1212 | 1336 ngx_ssl_conn_t *ssl_conn; |
1213 ngx_quic_header_t pkt = { 0 }; | 1337 |
1214 | |
1215 pkt.buf.data = b->start; | |
1216 pkt.buf.len = b->last - b->pos; | |
1217 | |
1218 if (ngx_buf_size(b) < 1200) { | |
1219 ngx_log_error(NGX_LOG_INFO, c->log, 0, "too small UDP datagram"); | |
1220 return NGX_ERROR; | |
1221 } | |
1222 | |
1223 if (ngx_quic_process_long_header(c, &pkt) != NGX_OK) { | |
1224 return NGX_ERROR; | |
1225 } | |
1226 | |
1227 if ((pkt.flags & 0xf0) != NGX_QUIC_PKT_INITIAL) { | |
1228 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1229 "invalid initial packet: 0x%xi", pkt.flags); | |
1230 return NGX_ERROR; | |
1231 } | |
1232 | |
1233 if (ngx_quic_process_initial_header(c, &pkt) != NGX_OK) { | |
1234 return NGX_ERROR; | |
1235 } | |
1236 | |
1237 qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t)); | |
1238 if (qc == NULL) { | |
1239 return NGX_ERROR; | |
1240 } | |
1241 | |
1242 c->quic = qc; | |
1243 | |
1244 qc->dcid.len = pkt.dcid.len; | |
1245 qc->dcid.data = ngx_pnalloc(c->pool, pkt.dcid.len); | |
1246 if (qc->dcid.data == NULL) { | |
1247 return NGX_ERROR; | |
1248 } | |
1249 ngx_memcpy(qc->dcid.data, pkt.dcid.data, qc->dcid.len); | |
1250 | |
1251 qc->scid.len = pkt.scid.len; | |
1252 qc->scid.data = ngx_pnalloc(c->pool, qc->scid.len); | |
1253 if (qc->scid.data == NULL) { | |
1254 return NGX_ERROR; | |
1255 } | |
1256 ngx_memcpy(qc->scid.data, pkt.scid.data, qc->scid.len); | |
1257 | |
1258 qc->token.len = pkt.token.len; | |
1259 qc->token.data = ngx_pnalloc(c->pool, qc->token.len); | |
1260 if (qc->token.data == NULL) { | |
1261 return NGX_ERROR; | |
1262 } | |
1263 ngx_memcpy(qc->token.data, pkt.token.data, qc->token.len); | |
1264 | |
1265 | |
1266 if (ngx_quic_initial_secret(c) != NGX_OK) { | |
1267 return NGX_ERROR; | |
1268 } | |
1269 | |
1270 pkt.secret = &qc->client_in; | |
1271 | |
1272 if (ngx_quic_decrypt(c, &pkt) != NGX_OK) { | |
1273 return NGX_ERROR; | |
1274 } | |
1275 | |
1276 out = pkt.payload; | |
1277 | |
1278 if (out.data[0] != NGX_QUIC_FT_CRYPTO) { | |
1279 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1280 "unexpected frame in initial packet"); | |
1281 return NGX_ERROR; | |
1282 } | |
1283 | |
1284 if (out.data[1] != 0x00) { | |
1285 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1286 "unexpected CRYPTO offset in initial packet"); | |
1287 return NGX_ERROR; | |
1288 } | |
1289 | |
1290 uint8_t *crypto = &out.data[2]; | |
1291 uint64_t crypto_len = ngx_quic_parse_int(&crypto); | |
1292 | |
1293 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1294 "quic initial packet CRYPTO length: %uL pp:%p:%p", | |
1295 crypto_len, out.data, crypto); | |
1296 | |
1297 if (ngx_ssl_create_connection(ssl, c, NGX_SSL_BUFFER) != NGX_OK) { | |
1298 return NGX_ERROR; | |
1299 } | |
1300 | |
1301 /* STUB: initial_max_streams_uni=3, active_connection_id_limit=5 */ | |
1302 static const uint8_t params[12] = "\x00\x0a\x00\x0e\x00\x01\x05\x00\x09\x00\x01\x03"; | |
1303 | |
1304 if (SSL_set_quic_transport_params(c->ssl->connection, params, | |
1305 sizeof(params)) == 0) | |
1306 { | |
1307 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1308 "SSL_set_quic_transport_params() failed"); | |
1309 return NGX_ERROR; | |
1310 } | |
1311 | |
1312 n = SSL_do_handshake(c->ssl->connection); | |
1313 | |
1314 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n); | |
1315 | |
1316 if (n == -1) { | |
1317 sslerr = SSL_get_error(c->ssl->connection, n); | |
1318 | |
1319 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", | |
1320 sslerr); | |
1321 } | |
1322 | |
1323 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1324 "SSL_quic_read_level: %d, SSL_quic_write_level: %d", | |
1325 (int) SSL_quic_read_level(c->ssl->connection), | |
1326 (int) SSL_quic_write_level(c->ssl->connection)); | |
1327 | |
1328 if (!SSL_provide_quic_data(c->ssl->connection, | |
1329 SSL_quic_read_level(c->ssl->connection), | |
1330 crypto, crypto_len)) | |
1331 { | |
1332 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, | |
1333 "SSL_provide_quic_data() failed"); | |
1334 return NGX_ERROR; | |
1335 } | |
1336 | |
1337 n = SSL_do_handshake(c->ssl->connection); | |
1338 | |
1339 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n); | |
1340 | |
1341 if (n == -1) { | |
1342 sslerr = SSL_get_error(c->ssl->connection, n); | |
1343 | |
1344 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", | |
1345 sslerr); | |
1346 | |
1347 if (sslerr == SSL_ERROR_SSL) { | |
1348 ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "SSL_do_handshake() failed"); | |
1349 } | |
1350 } | |
1351 | |
1352 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1353 "SSL_quic_read_level: %d, SSL_quic_write_level: %d", | |
1354 (int) SSL_quic_read_level(c->ssl->connection), | |
1355 (int) SSL_quic_write_level(c->ssl->connection)); | |
1356 | |
1357 return NGX_OK; | |
1358 } | |
1359 | |
1360 | |
1361 static ngx_int_t | |
1362 ngx_quic_handshake_input(ngx_connection_t *c, ngx_buf_t *b) | |
1363 { | |
1364 int sslerr; | |
1365 ssize_t n; | |
1366 ngx_str_t out; | |
1367 ngx_ssl_conn_t *ssl_conn; | |
1368 ngx_quic_connection_t *qc; | |
1369 | |
1370 ngx_quic_header_t pkt = { 0 }; | |
1371 | |
1372 qc = c->quic; | |
1373 ssl_conn = c->ssl->connection; | 1338 ssl_conn = c->ssl->connection; |
1374 | |
1375 pkt.buf.data = b->start; | |
1376 pkt.buf.len = b->last - b->pos; | |
1377 | |
1378 /* extract cleartext data into pkt */ | |
1379 if (ngx_quic_process_long_header(c, &pkt) != NGX_OK) { | |
1380 return NGX_ERROR; | |
1381 } | |
1382 | |
1383 if (pkt.dcid.len != qc->dcid.len) { | |
1384 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcidl"); | |
1385 return NGX_ERROR; | |
1386 } | |
1387 | |
1388 if (ngx_memcmp(pkt.dcid.data, qc->dcid.data, qc->dcid.len) != 0) { | |
1389 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcid"); | |
1390 return NGX_ERROR; | |
1391 } | |
1392 | |
1393 if (pkt.scid.len != qc->scid.len) { | |
1394 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic scidl"); | |
1395 return NGX_ERROR; | |
1396 } | |
1397 | |
1398 if (ngx_memcmp(pkt.scid.data, qc->scid.data, qc->scid.len) != 0) { | |
1399 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic scid"); | |
1400 return NGX_ERROR; | |
1401 } | |
1402 | |
1403 if ((pkt.flags & 0xf0) != NGX_QUIC_PKT_HANDSHAKE) { | |
1404 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1405 "invalid packet type: 0x%xi", pkt.flags); | |
1406 return NGX_ERROR; | |
1407 } | |
1408 | |
1409 if (ngx_quic_process_handshake_header(c, &pkt) != NGX_OK) { | |
1410 return NGX_ERROR; | |
1411 } | |
1412 | |
1413 pkt.secret = &qc->client_hs; | |
1414 | |
1415 if (ngx_quic_decrypt(c, &pkt) != NGX_OK) { | |
1416 return NGX_ERROR; | |
1417 } | |
1418 | |
1419 out = pkt.payload; | |
1420 | |
1421 if (out.data[0] != NGX_QUIC_FT_CRYPTO) { | |
1422 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1423 "non-CRYPTO frame in HS packet, skipping"); | |
1424 return NGX_OK; | |
1425 } | |
1426 | |
1427 if (out.data[1] != 0x00) { | |
1428 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1429 "not yet supported CRYPTO offset in initial packet"); | |
1430 return NGX_ERROR; | |
1431 } | |
1432 | |
1433 uint8_t *crypto = &out.data[2]; | |
1434 uint64_t crypto_len = ngx_quic_parse_int(&crypto); | |
1435 | |
1436 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1437 "quic Handshake packet CRYPTO length: %uL pp:%p:%p", | |
1438 crypto_len, out.data, crypto); | |
1439 | 1339 |
1440 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 1340 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
1441 "SSL_quic_read_level: %d, SSL_quic_write_level: %d", | 1341 "SSL_quic_read_level: %d, SSL_quic_write_level: %d", |
1442 (int) SSL_quic_read_level(ssl_conn), | 1342 (int) SSL_quic_read_level(ssl_conn), |
1443 (int) SSL_quic_write_level(ssl_conn)); | 1343 (int) SSL_quic_write_level(ssl_conn)); |
1444 | 1344 |
1345 | |
1445 if (!SSL_provide_quic_data(ssl_conn, SSL_quic_read_level(ssl_conn), | 1346 if (!SSL_provide_quic_data(ssl_conn, SSL_quic_read_level(ssl_conn), |
1446 crypto, crypto_len)) | 1347 frame->u.crypto.data, frame->u.crypto.len)) |
1447 { | 1348 { |
1448 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, | 1349 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, |
1449 "SSL_provide_quic_data() failed"); | 1350 "SSL_provide_quic_data() failed"); |
1450 return NGX_ERROR; | 1351 return NGX_ERROR; |
1451 } | 1352 } |
1462 | 1363 |
1463 if (sslerr == SSL_ERROR_SSL) { | 1364 if (sslerr == SSL_ERROR_SSL) { |
1464 ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "SSL_do_handshake() failed"); | 1365 ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "SSL_do_handshake() failed"); |
1465 } | 1366 } |
1466 } | 1367 } |
1368 | |
1369 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1370 "quic ssl cipher: %s", SSL_get_cipher(ssl_conn)); | |
1467 | 1371 |
1468 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 1372 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
1469 "SSL_quic_read_level: %d, SSL_quic_write_level: %d", | 1373 "SSL_quic_read_level: %d, SSL_quic_write_level: %d", |
1470 (int) SSL_quic_read_level(ssl_conn), | 1374 (int) SSL_quic_read_level(ssl_conn), |
1471 (int) SSL_quic_write_level(ssl_conn)); | 1375 (int) SSL_quic_write_level(ssl_conn)); |
1472 | 1376 |
1473 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1474 "quic ssl cipher: %s", SSL_get_cipher(ssl_conn)); | |
1475 | |
1476 // ACK Client Finished | |
1477 | |
1478 ngx_quic_frame_t *frame; | |
1479 | |
1480 frame = ngx_pcalloc(c->pool, sizeof(ngx_quic_frame_t)); | |
1481 if (frame == NULL) { | |
1482 return 0; | |
1483 } | |
1484 | |
1485 frame->level = ssl_encryption_handshake; | |
1486 frame->type = NGX_QUIC_FT_ACK; | |
1487 frame->u.ack.pn = pkt.pn; | |
1488 | |
1489 ngx_sprintf(frame->info, "ACK for PN=%d at handshake level, in respond to client finished", pkt.pn); | |
1490 ngx_quic_queue_frame(qc, frame); | |
1491 | |
1492 if (ngx_quic_output(c) != NGX_OK) { | |
1493 return 0; | |
1494 } | |
1495 | |
1496 return NGX_OK; | 1377 return NGX_OK; |
1378 } | |
1379 | |
1380 | |
1381 | |
1382 static ngx_int_t | |
1383 ngx_quic_init_connection(ngx_connection_t *c, ngx_quic_header_t *pkt) | |
1384 { | |
1385 int n, sslerr; | |
1386 ngx_ssl_conn_t *ssl_conn; | |
1387 ngx_quic_connection_t *qc; | |
1388 | |
1389 /* STUB: initial_max_streams_uni=3, active_connection_id_limit=5 */ | |
1390 static const uint8_t params[12] = "\x00\x0a\x00\x0e\x00\x01\x05\x00\x09\x00\x01\x03"; | |
1391 | |
1392 qc = c->quic; | |
1393 | |
1394 if (ngx_ssl_create_connection(qc->ssl, c, NGX_SSL_BUFFER) != NGX_OK) { | |
1395 return NGX_ERROR; | |
1396 } | |
1397 | |
1398 ssl_conn = c->ssl->connection; | |
1399 | |
1400 if (SSL_set_quic_transport_params(ssl_conn, params, sizeof(params)) == 0) { | |
1401 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1402 "SSL_set_quic_transport_params() failed"); | |
1403 return NGX_ERROR; | |
1404 } | |
1405 | |
1406 n = SSL_do_handshake(ssl_conn); | |
1407 | |
1408 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n); | |
1409 | |
1410 if (n == -1) { | |
1411 sslerr = SSL_get_error(ssl_conn, n); | |
1412 | |
1413 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", | |
1414 sslerr); | |
1415 } | |
1416 | |
1417 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1418 "SSL_quic_read_level: %d, SSL_quic_write_level: %d", | |
1419 (int) SSL_quic_read_level(ssl_conn), | |
1420 (int) SSL_quic_write_level(ssl_conn)); | |
1421 | |
1422 return NGX_OK; | |
1423 } | |
1424 | |
1425 | |
1426 /* process all payload from the current packet and generate ack if required */ | |
1427 static ngx_int_t | |
1428 ngx_quic_payload_handler(ngx_connection_t *c, ngx_quic_header_t *pkt) | |
1429 { | |
1430 u_char *end; | |
1431 ngx_uint_t ack_this; | |
1432 ngx_quic_frame_t frame, *ack_frame; | |
1433 ngx_quic_connection_t *qc; | |
1434 | |
1435 qc = c->quic; | |
1436 end = pkt->payload.data + pkt->payload.len; | |
1437 | |
1438 ack_this = 0; | |
1439 | |
1440 while (pkt->pos < end) { | |
1441 | |
1442 if (ngx_quic_read_frame(c, pkt, &frame) != NGX_OK) { | |
1443 return NGX_ERROR; | |
1444 } | |
1445 | |
1446 switch (frame.type) { | |
1447 | |
1448 case NGX_QUIC_FT_ACK: | |
1449 | |
1450 // TODO: handle ack | |
1451 | |
1452 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1453 "ACK: { largest=%ui delay=%ui first=%ui count=%ui}", | |
1454 frame.u.ack.largest, | |
1455 frame.u.ack.delay, | |
1456 frame.u.ack.first_range, | |
1457 frame.u.ack.range_count); | |
1458 | |
1459 break; | |
1460 | |
1461 case NGX_QUIC_FT_CRYPTO: | |
1462 | |
1463 if (frame.u.crypto.offset != 0x0) { | |
1464 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1465 "crypto frame with non-zero offset"); | |
1466 // TODO: support packet spanning with offsets | |
1467 return NGX_ERROR; | |
1468 } | |
1469 | |
1470 if (ngx_quic_handle_crypto_frame(c, pkt, &frame) != NGX_OK) { | |
1471 return NGX_ERROR; | |
1472 } | |
1473 | |
1474 ack_this = 1; | |
1475 | |
1476 continue; | |
1477 | |
1478 case NGX_QUIC_FT_PADDING: | |
1479 continue; | |
1480 | |
1481 case NGX_QUIC_FT_PING: | |
1482 ack_this = 1; | |
1483 continue; | |
1484 | |
1485 default: | |
1486 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1487 "unexpected frame type 0x%xd in packet", frame.type); | |
1488 return NGX_ERROR; | |
1489 } | |
1490 } | |
1491 | |
1492 if (ack_this == 0) { | |
1493 /* do not ack packets with ACKs and PADDING */ | |
1494 return NGX_OK; | |
1495 } | |
1496 | |
1497 // packet processed, ACK it now if required | |
1498 // TODO: if (ack_required) ... - currently just ack each packet | |
1499 | |
1500 ack_frame = ngx_pcalloc(c->pool, sizeof(ngx_quic_frame_t)); | |
1501 if (ack_frame == NULL) { | |
1502 return NGX_ERROR; | |
1503 } | |
1504 | |
1505 ack_frame->level = pkt->level; | |
1506 ack_frame->type = NGX_QUIC_FT_ACK; | |
1507 ack_frame->u.ack.pn = pkt->pn; | |
1508 | |
1509 ngx_sprintf(ack_frame->info, "ACK for PN=%d from frame handler", pkt->pn); | |
1510 ngx_quic_queue_frame(qc, ack_frame); | |
1511 | |
1512 return ngx_quic_output(c); | |
1513 } | |
1514 | |
1515 | |
1516 static ngx_int_t | |
1517 ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b) | |
1518 { | |
1519 ngx_quic_connection_t *qc; | |
1520 | |
1521 ngx_quic_header_t pkt = { 0 }; | |
1522 | |
1523 pkt.buf.data = b->start; | |
1524 pkt.buf.len = b->last - b->pos; | |
1525 | |
1526 if (ngx_buf_size(b) < 1200) { | |
1527 ngx_log_error(NGX_LOG_INFO, c->log, 0, "too small UDP datagram"); | |
1528 return NGX_ERROR; | |
1529 } | |
1530 | |
1531 if (ngx_quic_process_long_header(c, &pkt) != NGX_OK) { | |
1532 return NGX_ERROR; | |
1533 } | |
1534 | |
1535 if ((pkt.flags & 0xf0) != NGX_QUIC_PKT_INITIAL) { | |
1536 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1537 "invalid initial packet: 0x%xi", pkt.flags); | |
1538 return NGX_ERROR; | |
1539 } | |
1540 | |
1541 if (ngx_quic_process_initial_header(c, &pkt) != NGX_OK) { | |
1542 return NGX_ERROR; | |
1543 } | |
1544 | |
1545 qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t)); | |
1546 if (qc == NULL) { | |
1547 return NGX_ERROR; | |
1548 } | |
1549 | |
1550 c->quic = qc; | |
1551 qc->ssl = ssl; | |
1552 | |
1553 qc->dcid.len = pkt.dcid.len; | |
1554 qc->dcid.data = ngx_pnalloc(c->pool, pkt.dcid.len); | |
1555 if (qc->dcid.data == NULL) { | |
1556 return NGX_ERROR; | |
1557 } | |
1558 ngx_memcpy(qc->dcid.data, pkt.dcid.data, qc->dcid.len); | |
1559 | |
1560 qc->scid.len = pkt.scid.len; | |
1561 qc->scid.data = ngx_pnalloc(c->pool, qc->scid.len); | |
1562 if (qc->scid.data == NULL) { | |
1563 return NGX_ERROR; | |
1564 } | |
1565 ngx_memcpy(qc->scid.data, pkt.scid.data, qc->scid.len); | |
1566 | |
1567 qc->token.len = pkt.token.len; | |
1568 qc->token.data = ngx_pnalloc(c->pool, qc->token.len); | |
1569 if (qc->token.data == NULL) { | |
1570 return NGX_ERROR; | |
1571 } | |
1572 ngx_memcpy(qc->token.data, pkt.token.data, qc->token.len); | |
1573 | |
1574 | |
1575 if (ngx_quic_initial_secret(c) != NGX_OK) { | |
1576 return NGX_ERROR; | |
1577 } | |
1578 | |
1579 pkt.secret = &qc->client_in; | |
1580 pkt.level = ssl_encryption_initial; | |
1581 | |
1582 if (ngx_quic_decrypt(c, &pkt) != NGX_OK) { | |
1583 return NGX_ERROR; | |
1584 } | |
1585 | |
1586 if (ngx_quic_init_connection(c, &pkt) != NGX_OK) { | |
1587 return NGX_ERROR; | |
1588 } | |
1589 | |
1590 return ngx_quic_payload_handler(c, &pkt); | |
1591 } | |
1592 | |
1593 | |
1594 static ngx_int_t | |
1595 ngx_quic_handshake_input(ngx_connection_t *c, ngx_buf_t *b) | |
1596 { | |
1597 ngx_ssl_conn_t *ssl_conn; | |
1598 ngx_quic_connection_t *qc; | |
1599 | |
1600 ngx_quic_header_t pkt = { 0 }; | |
1601 | |
1602 qc = c->quic; | |
1603 ssl_conn = c->ssl->connection; | |
1604 | |
1605 pkt.buf.data = b->start; | |
1606 pkt.buf.len = b->last - b->pos; | |
1607 | |
1608 /* extract cleartext data into pkt */ | |
1609 if (ngx_quic_process_long_header(c, &pkt) != NGX_OK) { | |
1610 return NGX_ERROR; | |
1611 } | |
1612 | |
1613 if (pkt.dcid.len != qc->dcid.len) { | |
1614 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcidl"); | |
1615 return NGX_ERROR; | |
1616 } | |
1617 | |
1618 if (ngx_memcmp(pkt.dcid.data, qc->dcid.data, qc->dcid.len) != 0) { | |
1619 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcid"); | |
1620 return NGX_ERROR; | |
1621 } | |
1622 | |
1623 if (pkt.scid.len != qc->scid.len) { | |
1624 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic scidl"); | |
1625 return NGX_ERROR; | |
1626 } | |
1627 | |
1628 if (ngx_memcmp(pkt.scid.data, qc->scid.data, qc->scid.len) != 0) { | |
1629 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic scid"); | |
1630 return NGX_ERROR; | |
1631 } | |
1632 | |
1633 if ((pkt.flags & 0xf0) != NGX_QUIC_PKT_HANDSHAKE) { | |
1634 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1635 "invalid packet type: 0x%xi", pkt.flags); | |
1636 return NGX_ERROR; | |
1637 } | |
1638 | |
1639 if (ngx_quic_process_handshake_header(c, &pkt) != NGX_OK) { | |
1640 return NGX_ERROR; | |
1641 } | |
1642 | |
1643 pkt.secret = &qc->client_hs; | |
1644 pkt.level = ssl_encryption_handshake; | |
1645 | |
1646 if (ngx_quic_decrypt(c, &pkt) != NGX_OK) { | |
1647 return NGX_ERROR; | |
1648 } | |
1649 | |
1650 return ngx_quic_payload_handler(c, &pkt); | |
1651 } | |
1652 | |
1653 | |
1654 static ngx_int_t | |
1655 ngx_quic_app_input(ngx_connection_t *c, ngx_buf_t *b) | |
1656 { | |
1657 ngx_quic_connection_t *qc; | |
1658 | |
1659 qc = c->quic; | |
1660 | |
1661 /* TODO: this is a stub, untested */ | |
1662 | |
1663 ngx_quic_header_t pkt = { 0 }; | |
1664 | |
1665 pkt.buf.data = b->start; | |
1666 pkt.buf.len = b->last - b->pos; | |
1667 | |
1668 if (ngx_quic_process_short_header(c, &pkt) != NGX_OK) { | |
1669 return NGX_ERROR; | |
1670 } | |
1671 | |
1672 pkt.secret = &qc->client_ad; | |
1673 pkt.level = ssl_encryption_application; | |
1674 | |
1675 if (ngx_quic_decrypt(c, &pkt) != NGX_OK) { | |
1676 return NGX_ERROR; | |
1677 } | |
1678 | |
1679 return ngx_quic_payload_handler(c, &pkt); | |
1497 } | 1680 } |
1498 | 1681 |
1499 | 1682 |
1500 uint64_t | 1683 uint64_t |
1501 ngx_quic_parse_int(u_char **pos) | 1684 ngx_quic_parse_int(u_char **pos) |