Mercurial > hg > nginx
comparison src/core/ngx_resolver.c @ 6367:5a16d40c63de
Resolver: TCP support.
Resend DNS query over TCP once UDP response came truncated.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Thu, 28 Jan 2016 15:28:20 +0300 |
parents | 2e5c027f2a98 |
children | d73f77bb5caf |
comparison
equal
deleted
inserted
replaced
6366:2e5c027f2a98 | 6367:5a16d40c63de |
---|---|
9 #include <ngx_core.h> | 9 #include <ngx_core.h> |
10 #include <ngx_event.h> | 10 #include <ngx_event.h> |
11 | 11 |
12 | 12 |
13 #define NGX_RESOLVER_UDP_SIZE 4096 | 13 #define NGX_RESOLVER_UDP_SIZE 4096 |
14 | |
15 #define NGX_RESOLVER_TCP_RSIZE (2 + 65535) | |
16 #define NGX_RESOLVER_TCP_WSIZE 8192 | |
14 | 17 |
15 | 18 |
16 typedef struct { | 19 typedef struct { |
17 u_char ident_hi; | 20 u_char ident_hi; |
18 u_char ident_lo; | 21 u_char ident_lo; |
52 (ngx_resolver_node_t *) \ | 55 (ngx_resolver_node_t *) \ |
53 ((u_char *) (n) - offsetof(ngx_resolver_node_t, node)) | 56 ((u_char *) (n) - offsetof(ngx_resolver_node_t, node)) |
54 | 57 |
55 | 58 |
56 ngx_int_t ngx_udp_connect(ngx_resolver_connection_t *rec); | 59 ngx_int_t ngx_udp_connect(ngx_resolver_connection_t *rec); |
60 ngx_int_t ngx_tcp_connect(ngx_resolver_connection_t *rec); | |
57 | 61 |
58 | 62 |
59 static void ngx_resolver_cleanup(void *data); | 63 static void ngx_resolver_cleanup(void *data); |
60 static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree); | 64 static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree); |
61 static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r, | 65 static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r, |
62 ngx_resolver_ctx_t *ctx, ngx_str_t *name); | 66 ngx_resolver_ctx_t *ctx, ngx_str_t *name); |
63 static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, | 67 static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, |
64 ngx_queue_t *queue); | 68 ngx_queue_t *queue); |
65 static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r, | 69 static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r, |
66 ngx_resolver_node_t *rn); | 70 ngx_resolver_node_t *rn); |
71 static ngx_int_t ngx_resolver_send_udp_query(ngx_resolver_t *r, | |
72 ngx_resolver_connection_t *rec, u_char *query, u_short qlen); | |
73 static ngx_int_t ngx_resolver_send_tcp_query(ngx_resolver_t *r, | |
74 ngx_resolver_connection_t *rec, u_char *query, u_short qlen); | |
67 static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r, | 75 static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r, |
68 ngx_resolver_node_t *rn, ngx_str_t *name); | 76 ngx_resolver_node_t *rn, ngx_str_t *name); |
69 static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r, | 77 static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r, |
70 ngx_resolver_node_t *rn, ngx_addr_t *addr); | 78 ngx_resolver_node_t *rn, ngx_addr_t *addr); |
71 static void ngx_resolver_resend_handler(ngx_event_t *ev); | 79 static void ngx_resolver_resend_handler(ngx_event_t *ev); |
72 static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, | 80 static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, |
73 ngx_queue_t *queue); | 81 ngx_queue_t *queue); |
74 static ngx_uint_t ngx_resolver_resend_empty(ngx_resolver_t *r); | 82 static ngx_uint_t ngx_resolver_resend_empty(ngx_resolver_t *r); |
75 static void ngx_resolver_read_response(ngx_event_t *rev); | 83 static void ngx_resolver_udp_read(ngx_event_t *rev); |
84 static void ngx_resolver_tcp_write(ngx_event_t *wev); | |
85 static void ngx_resolver_tcp_read(ngx_event_t *rev); | |
76 static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, | 86 static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, |
77 size_t n); | 87 size_t n, ngx_uint_t tcp); |
78 static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, | 88 static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, |
79 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype, | 89 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype, |
80 ngx_uint_t nan, ngx_uint_t ans); | 90 ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans); |
81 static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, | 91 static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, |
82 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan); | 92 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan); |
83 static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r, | 93 static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r, |
84 ngx_str_t *name, uint32_t hash); | 94 ngx_str_t *name, uint32_t hash); |
85 static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r, | 95 static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r, |
163 r->event->data = r; | 173 r->event->data = r; |
164 r->event->log = &cf->cycle->new_log; | 174 r->event->log = &cf->cycle->new_log; |
165 r->ident = -1; | 175 r->ident = -1; |
166 | 176 |
167 r->resend_timeout = 5; | 177 r->resend_timeout = 5; |
178 r->tcp_timeout = 5; | |
168 r->expire = 30; | 179 r->expire = 30; |
169 r->valid = 0; | 180 r->valid = 0; |
170 | 181 |
171 r->log = &cf->cycle->new_log; | 182 r->log = &cf->cycle->new_log; |
172 r->log_level = NGX_LOG_ERR; | 183 r->log_level = NGX_LOG_ERR; |
239 | 250 |
240 for (j = 0; j < u.naddrs; j++) { | 251 for (j = 0; j < u.naddrs; j++) { |
241 rec[j].sockaddr = u.addrs[j].sockaddr; | 252 rec[j].sockaddr = u.addrs[j].sockaddr; |
242 rec[j].socklen = u.addrs[j].socklen; | 253 rec[j].socklen = u.addrs[j].socklen; |
243 rec[j].server = u.addrs[j].name; | 254 rec[j].server = u.addrs[j].name; |
255 rec[j].resolver = r; | |
244 } | 256 } |
245 } | 257 } |
246 | 258 |
247 return r; | 259 return r; |
248 } | 260 } |
276 rec = r->connections.elts; | 288 rec = r->connections.elts; |
277 | 289 |
278 for (i = 0; i < r->connections.nelts; i++) { | 290 for (i = 0; i < r->connections.nelts; i++) { |
279 if (rec[i].udp) { | 291 if (rec[i].udp) { |
280 ngx_close_connection(rec[i].udp); | 292 ngx_close_connection(rec[i].udp); |
293 } | |
294 | |
295 if (rec[i].tcp) { | |
296 ngx_close_connection(rec[i].tcp); | |
281 } | 297 } |
282 } | 298 } |
283 | 299 |
284 ngx_free(r); | 300 ngx_free(r); |
285 } | 301 } |
689 if (r->last_connection == r->connections.nelts) { | 705 if (r->last_connection == r->connections.nelts) { |
690 r->last_connection = 0; | 706 r->last_connection = 0; |
691 } | 707 } |
692 | 708 |
693 rn->naddrs = (u_short) -1; | 709 rn->naddrs = (u_short) -1; |
710 rn->tcp = 0; | |
694 #if (NGX_HAVE_INET6) | 711 #if (NGX_HAVE_INET6) |
695 rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0; | 712 rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0; |
713 rn->tcp6 = 0; | |
696 #endif | 714 #endif |
697 | 715 |
698 if (ngx_resolver_send_query(r, rn) != NGX_OK) { | 716 if (ngx_resolver_send_query(r, rn) != NGX_OK) { |
699 goto failed; | 717 goto failed; |
700 } | 718 } |
906 if (r->last_connection == r->connections.nelts) { | 924 if (r->last_connection == r->connections.nelts) { |
907 r->last_connection = 0; | 925 r->last_connection = 0; |
908 } | 926 } |
909 | 927 |
910 rn->naddrs = (u_short) -1; | 928 rn->naddrs = (u_short) -1; |
929 rn->tcp = 0; | |
911 #if (NGX_HAVE_INET6) | 930 #if (NGX_HAVE_INET6) |
912 rn->naddrs6 = (u_short) -1; | 931 rn->naddrs6 = (u_short) -1; |
932 rn->tcp6 = 0; | |
913 #endif | 933 #endif |
914 | 934 |
915 if (ngx_resolver_send_query(r, rn) != NGX_OK) { | 935 if (ngx_resolver_send_query(r, rn) != NGX_OK) { |
916 goto failed; | 936 goto failed; |
917 } | 937 } |
1102 | 1122 |
1103 | 1123 |
1104 static ngx_int_t | 1124 static ngx_int_t |
1105 ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn) | 1125 ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn) |
1106 { | 1126 { |
1107 ssize_t n; | 1127 ngx_int_t rc; |
1108 ngx_resolver_connection_t *rec; | 1128 ngx_resolver_connection_t *rec; |
1109 | 1129 |
1110 rec = r->connections.elts; | 1130 rec = r->connections.elts; |
1111 rec = &rec[rn->last_connection]; | 1131 rec = &rec[rn->last_connection]; |
1112 | 1132 |
1113 if (rec->udp == NULL) { | 1133 if (rec->log.handler == NULL) { |
1114 | |
1115 rec->log = *r->log; | 1134 rec->log = *r->log; |
1116 rec->log.handler = ngx_resolver_log_error; | 1135 rec->log.handler = ngx_resolver_log_error; |
1117 rec->log.data = rec; | 1136 rec->log.data = rec; |
1118 rec->log.action = "resolving"; | 1137 rec->log.action = "resolving"; |
1119 | 1138 } |
1139 | |
1140 if (rn->naddrs == (u_short) -1) { | |
1141 rc = rn->tcp ? ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen) | |
1142 : ngx_resolver_send_udp_query(r, rec, rn->query, rn->qlen); | |
1143 | |
1144 if (rc != NGX_OK) { | |
1145 return rc; | |
1146 } | |
1147 } | |
1148 | |
1149 #if (NGX_HAVE_INET6) | |
1150 | |
1151 if (rn->query6 && rn->naddrs6 == (u_short) -1) { | |
1152 rc = rn->tcp6 | |
1153 ? ngx_resolver_send_tcp_query(r, rec, rn->query6, rn->qlen) | |
1154 : ngx_resolver_send_udp_query(r, rec, rn->query6, rn->qlen); | |
1155 | |
1156 if (rc != NGX_OK) { | |
1157 return rc; | |
1158 } | |
1159 } | |
1160 | |
1161 #endif | |
1162 | |
1163 return NGX_OK; | |
1164 } | |
1165 | |
1166 | |
1167 static ngx_int_t | |
1168 ngx_resolver_send_udp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec, | |
1169 u_char *query, u_short qlen) | |
1170 { | |
1171 ssize_t n; | |
1172 | |
1173 if (rec->udp == NULL) { | |
1120 if (ngx_udp_connect(rec) != NGX_OK) { | 1174 if (ngx_udp_connect(rec) != NGX_OK) { |
1121 return NGX_ERROR; | 1175 return NGX_ERROR; |
1122 } | 1176 } |
1123 | 1177 |
1124 rec->udp->data = r; | 1178 rec->udp->data = rec; |
1125 rec->udp->read->handler = ngx_resolver_read_response; | 1179 rec->udp->read->handler = ngx_resolver_udp_read; |
1126 rec->udp->read->resolver = 1; | 1180 rec->udp->read->resolver = 1; |
1127 } | 1181 } |
1128 | 1182 |
1129 if (rn->naddrs == (u_short) -1) { | 1183 n = ngx_send(rec->udp, query, qlen); |
1130 n = ngx_send(rec->udp, rn->query, rn->qlen); | 1184 |
1131 | 1185 if (n == -1) { |
1132 if (n == -1) { | 1186 return NGX_ERROR; |
1187 } | |
1188 | |
1189 if ((size_t) n != (size_t) qlen) { | |
1190 ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "send() incomplete"); | |
1191 return NGX_ERROR; | |
1192 } | |
1193 | |
1194 return NGX_OK; | |
1195 } | |
1196 | |
1197 | |
1198 static ngx_int_t | |
1199 ngx_resolver_send_tcp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec, | |
1200 u_char *query, u_short qlen) | |
1201 { | |
1202 ngx_buf_t *b; | |
1203 ngx_int_t rc; | |
1204 | |
1205 rc = NGX_OK; | |
1206 | |
1207 if (rec->tcp == NULL) { | |
1208 b = rec->read_buf; | |
1209 | |
1210 if (b == NULL) { | |
1211 b = ngx_resolver_calloc(r, sizeof(ngx_buf_t)); | |
1212 if (b == NULL) { | |
1213 return NGX_ERROR; | |
1214 } | |
1215 | |
1216 b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_RSIZE); | |
1217 if (b->start == NULL) { | |
1218 return NGX_ERROR; | |
1219 } | |
1220 | |
1221 b->end = b->start + NGX_RESOLVER_TCP_RSIZE; | |
1222 | |
1223 rec->read_buf = b; | |
1224 } | |
1225 | |
1226 b->pos = b->start; | |
1227 b->last = b->start; | |
1228 | |
1229 b = rec->write_buf; | |
1230 | |
1231 if (b == NULL) { | |
1232 b = ngx_resolver_calloc(r, sizeof(ngx_buf_t)); | |
1233 if (b == NULL) { | |
1234 return NGX_ERROR; | |
1235 } | |
1236 | |
1237 b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_WSIZE); | |
1238 if (b->start == NULL) { | |
1239 return NGX_ERROR; | |
1240 } | |
1241 | |
1242 b->end = b->start + NGX_RESOLVER_TCP_WSIZE; | |
1243 | |
1244 rec->write_buf = b; | |
1245 } | |
1246 | |
1247 b->pos = b->start; | |
1248 b->last = b->start; | |
1249 | |
1250 rc = ngx_tcp_connect(rec); | |
1251 if (rc == NGX_ERROR) { | |
1133 return NGX_ERROR; | 1252 return NGX_ERROR; |
1134 } | 1253 } |
1135 | 1254 |
1136 if ((size_t) n != (size_t) rn->qlen) { | 1255 rec->tcp->data = rec; |
1137 ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "send() incomplete"); | 1256 rec->tcp->write->handler = ngx_resolver_tcp_write; |
1138 return NGX_ERROR; | 1257 rec->tcp->read->handler = ngx_resolver_tcp_read; |
1139 } | 1258 rec->tcp->read->resolver = 1; |
1140 } | 1259 |
1141 | 1260 ngx_add_timer(rec->tcp->write, (ngx_msec_t) (r->tcp_timeout * 1000)); |
1142 #if (NGX_HAVE_INET6) | 1261 } |
1143 if (rn->query6 && rn->naddrs6 == (u_short) -1) { | 1262 |
1144 n = ngx_send(rec->udp, rn->query6, rn->qlen); | 1263 b = rec->write_buf; |
1145 | 1264 |
1146 if (n == -1) { | 1265 if (b->end - b->last < 2 + qlen) { |
1147 return NGX_ERROR; | 1266 ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "buffer overflow"); |
1148 } | 1267 return NGX_ERROR; |
1149 | 1268 } |
1150 if ((size_t) n != (size_t) rn->qlen) { | 1269 |
1151 ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "send() incomplete"); | 1270 *b->last++ = (u_char) (qlen >> 8); |
1152 return NGX_ERROR; | 1271 *b->last++ = (u_char) qlen; |
1153 } | 1272 b->last = ngx_cpymem(b->last, query, qlen); |
1154 } | 1273 |
1155 #endif | 1274 if (rc == NGX_OK) { |
1275 ngx_resolver_tcp_write(rec->tcp->write); | |
1276 } | |
1156 | 1277 |
1157 return NGX_OK; | 1278 return NGX_OK; |
1158 } | 1279 } |
1159 | 1280 |
1160 | 1281 |
1280 && ngx_queue_empty(&r->addr_resend_queue); | 1401 && ngx_queue_empty(&r->addr_resend_queue); |
1281 } | 1402 } |
1282 | 1403 |
1283 | 1404 |
1284 static void | 1405 static void |
1285 ngx_resolver_read_response(ngx_event_t *rev) | 1406 ngx_resolver_udp_read(ngx_event_t *rev) |
1286 { | 1407 { |
1287 ssize_t n; | 1408 ssize_t n; |
1288 ngx_connection_t *c; | 1409 ngx_connection_t *c; |
1289 u_char buf[NGX_RESOLVER_UDP_SIZE]; | 1410 ngx_resolver_connection_t *rec; |
1411 u_char buf[NGX_RESOLVER_UDP_SIZE]; | |
1290 | 1412 |
1291 c = rev->data; | 1413 c = rev->data; |
1414 rec = c->data; | |
1292 | 1415 |
1293 do { | 1416 do { |
1294 n = ngx_udp_recv(c, buf, NGX_RESOLVER_UDP_SIZE); | 1417 n = ngx_udp_recv(c, buf, NGX_RESOLVER_UDP_SIZE); |
1295 | 1418 |
1296 if (n < 0) { | 1419 if (n < 0) { |
1297 return; | 1420 return; |
1298 } | 1421 } |
1299 | 1422 |
1300 ngx_resolver_process_response(c->data, buf, n); | 1423 ngx_resolver_process_response(rec->resolver, buf, n, 0); |
1301 | 1424 |
1302 } while (rev->ready); | 1425 } while (rev->ready); |
1303 } | 1426 } |
1304 | 1427 |
1305 | 1428 |
1306 static void | 1429 static void |
1307 ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n) | 1430 ngx_resolver_tcp_write(ngx_event_t *wev) |
1431 { | |
1432 off_t sent; | |
1433 ssize_t n; | |
1434 ngx_buf_t *b; | |
1435 ngx_resolver_t *r; | |
1436 ngx_connection_t *c; | |
1437 ngx_resolver_connection_t *rec; | |
1438 | |
1439 c = wev->data; | |
1440 rec = c->data; | |
1441 b = rec->write_buf; | |
1442 r = rec->resolver; | |
1443 | |
1444 if (wev->timedout) { | |
1445 goto failed; | |
1446 } | |
1447 | |
1448 sent = c->sent; | |
1449 | |
1450 while (wev->ready && b->pos < b->last) { | |
1451 n = ngx_send(c, b->pos, b->last - b->pos); | |
1452 | |
1453 if (n == NGX_AGAIN) { | |
1454 break; | |
1455 } | |
1456 | |
1457 if (n == NGX_ERROR) { | |
1458 goto failed; | |
1459 } | |
1460 | |
1461 b->pos += n; | |
1462 } | |
1463 | |
1464 if (b->pos != b->start) { | |
1465 b->last = ngx_movemem(b->start, b->pos, b->last - b->pos); | |
1466 b->pos = b->start; | |
1467 } | |
1468 | |
1469 if (c->sent != sent) { | |
1470 ngx_add_timer(wev, (ngx_msec_t) (r->tcp_timeout * 1000)); | |
1471 } | |
1472 | |
1473 if (ngx_handle_write_event(wev, 0) != NGX_OK) { | |
1474 goto failed; | |
1475 } | |
1476 | |
1477 return; | |
1478 | |
1479 failed: | |
1480 | |
1481 ngx_close_connection(c); | |
1482 rec->tcp = NULL; | |
1483 } | |
1484 | |
1485 | |
1486 static void | |
1487 ngx_resolver_tcp_read(ngx_event_t *rev) | |
1488 { | |
1489 u_char *p; | |
1490 size_t size; | |
1491 ssize_t n; | |
1492 u_short qlen; | |
1493 ngx_buf_t *b; | |
1494 ngx_resolver_t *r; | |
1495 ngx_connection_t *c; | |
1496 ngx_resolver_connection_t *rec; | |
1497 | |
1498 c = rev->data; | |
1499 rec = c->data; | |
1500 b = rec->read_buf; | |
1501 r = rec->resolver; | |
1502 | |
1503 while (rev->ready) { | |
1504 n = ngx_recv(c, b->last, b->end - b->last); | |
1505 | |
1506 if (n == NGX_AGAIN) { | |
1507 break; | |
1508 } | |
1509 | |
1510 if (n == NGX_ERROR || n == 0) { | |
1511 goto failed; | |
1512 } | |
1513 | |
1514 b->last += n; | |
1515 | |
1516 for ( ;; ) { | |
1517 p = b->pos; | |
1518 size = b->last - p; | |
1519 | |
1520 if (size < 2) { | |
1521 break; | |
1522 } | |
1523 | |
1524 qlen = (u_short) *p++ << 8; | |
1525 qlen += *p++; | |
1526 | |
1527 if (size < (size_t) (2 + qlen)) { | |
1528 break; | |
1529 } | |
1530 | |
1531 ngx_resolver_process_response(r, p, qlen, 1); | |
1532 | |
1533 b->pos += 2 + qlen; | |
1534 } | |
1535 | |
1536 if (b->pos != b->start) { | |
1537 b->last = ngx_movemem(b->start, b->pos, b->last - b->pos); | |
1538 b->pos = b->start; | |
1539 } | |
1540 } | |
1541 | |
1542 if (ngx_handle_read_event(rev, 0) != NGX_OK) { | |
1543 goto failed; | |
1544 } | |
1545 | |
1546 return; | |
1547 | |
1548 failed: | |
1549 | |
1550 ngx_close_connection(c); | |
1551 rec->tcp = NULL; | |
1552 } | |
1553 | |
1554 | |
1555 static void | |
1556 ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n, | |
1557 ngx_uint_t tcp) | |
1308 { | 1558 { |
1309 char *err; | 1559 char *err; |
1310 ngx_uint_t i, times, ident, qident, flags, code, nqs, nan, | 1560 ngx_uint_t i, times, ident, qident, flags, code, nqs, nan, trunc, |
1311 qtype, qclass; | 1561 qtype, qclass; |
1312 #if (NGX_HAVE_INET6) | 1562 #if (NGX_HAVE_INET6) |
1313 ngx_uint_t qident6; | 1563 ngx_uint_t qident6; |
1314 #endif | 1564 #endif |
1315 ngx_queue_t *q; | 1565 ngx_queue_t *q; |
1325 | 1575 |
1326 ident = (response->ident_hi << 8) + response->ident_lo; | 1576 ident = (response->ident_hi << 8) + response->ident_lo; |
1327 flags = (response->flags_hi << 8) + response->flags_lo; | 1577 flags = (response->flags_hi << 8) + response->flags_lo; |
1328 nqs = (response->nqs_hi << 8) + response->nqs_lo; | 1578 nqs = (response->nqs_hi << 8) + response->nqs_lo; |
1329 nan = (response->nan_hi << 8) + response->nan_lo; | 1579 nan = (response->nan_hi << 8) + response->nan_lo; |
1580 trunc = flags & 0x0200; | |
1330 | 1581 |
1331 ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0, | 1582 ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0, |
1332 "resolver DNS response %ui fl:%04Xui %ui/%ui/%ud/%ud", | 1583 "resolver DNS response %ui fl:%04Xui %ui/%ui/%ud/%ud", |
1333 ident, flags, nqs, nan, | 1584 ident, flags, nqs, nan, |
1334 (response->nns_hi << 8) + response->nns_lo, | 1585 (response->nns_hi << 8) + response->nns_lo, |
1335 (response->nar_hi << 8) + response->nar_lo); | 1586 (response->nar_hi << 8) + response->nar_lo); |
1336 | 1587 |
1337 /* response to a standard query */ | 1588 /* response to a standard query */ |
1338 if ((flags & 0xf870) != 0x8000) { | 1589 if ((flags & 0xf870) != 0x8000 || (trunc && tcp)) { |
1339 ngx_log_error(r->log_level, r->log, 0, | 1590 ngx_log_error(r->log_level, r->log, 0, |
1340 "invalid DNS response %ui fl:%04Xui", ident, flags); | 1591 "invalid %s DNS response %ui fl:%04Xui", |
1592 tcp ? "TCP" : "UDP", ident, flags); | |
1341 return; | 1593 return; |
1342 } | 1594 } |
1343 | 1595 |
1344 code = flags & 0xf; | 1596 code = flags & 0xf; |
1345 | 1597 |
1425 case NGX_RESOLVE_A: | 1677 case NGX_RESOLVE_A: |
1426 #if (NGX_HAVE_INET6) | 1678 #if (NGX_HAVE_INET6) |
1427 case NGX_RESOLVE_AAAA: | 1679 case NGX_RESOLVE_AAAA: |
1428 #endif | 1680 #endif |
1429 | 1681 |
1430 ngx_resolver_process_a(r, buf, n, ident, code, qtype, nan, | 1682 ngx_resolver_process_a(r, buf, n, ident, code, qtype, nan, trunc, |
1431 i + sizeof(ngx_resolver_qs_t)); | 1683 i + sizeof(ngx_resolver_qs_t)); |
1432 | 1684 |
1433 break; | 1685 break; |
1434 | 1686 |
1435 case NGX_RESOLVE_PTR: | 1687 case NGX_RESOLVE_PTR: |
1474 | 1726 |
1475 | 1727 |
1476 static void | 1728 static void |
1477 ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, | 1729 ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, |
1478 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype, | 1730 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype, |
1479 ngx_uint_t nan, ngx_uint_t ans) | 1731 ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans) |
1480 { | 1732 { |
1481 char *err; | 1733 char *err; |
1482 u_char *cname; | 1734 u_char *cname; |
1483 size_t len; | 1735 size_t len; |
1484 int32_t ttl; | 1736 int32_t ttl; |
1485 uint32_t hash; | 1737 uint32_t hash; |
1486 in_addr_t *addr; | 1738 in_addr_t *addr; |
1487 ngx_str_t name; | 1739 ngx_str_t name; |
1488 ngx_addr_t *addrs; | 1740 ngx_addr_t *addrs; |
1489 ngx_uint_t type, class, qident, naddrs, a, i, n, start; | 1741 ngx_uint_t type, class, qident, naddrs, a, i, n, start; |
1490 #if (NGX_HAVE_INET6) | 1742 #if (NGX_HAVE_INET6) |
1491 struct in6_addr *addr6; | 1743 struct in6_addr *addr6; |
1492 #endif | 1744 #endif |
1493 ngx_resolver_an_t *an; | 1745 ngx_resolver_an_t *an; |
1494 ngx_resolver_ctx_t *ctx, *next; | 1746 ngx_resolver_ctx_t *ctx, *next; |
1495 ngx_resolver_node_t *rn; | 1747 ngx_resolver_node_t *rn; |
1748 ngx_resolver_connection_t *rec; | |
1496 | 1749 |
1497 if (ngx_resolver_copy(r, &name, buf, | 1750 if (ngx_resolver_copy(r, &name, buf, |
1498 buf + sizeof(ngx_resolver_hdr_t), buf + last) | 1751 buf + sizeof(ngx_resolver_hdr_t), buf + last) |
1499 != NGX_OK) | 1752 != NGX_OK) |
1500 { | 1753 { |
1526 "unexpected response for %V", &name); | 1779 "unexpected response for %V", &name); |
1527 ngx_resolver_free(r, name.data); | 1780 ngx_resolver_free(r, name.data); |
1528 goto failed; | 1781 goto failed; |
1529 } | 1782 } |
1530 | 1783 |
1784 if (trunc && rn->tcp6) { | |
1785 ngx_resolver_free(r, name.data); | |
1786 goto failed; | |
1787 } | |
1788 | |
1531 qident = (rn->query6[0] << 8) + rn->query6[1]; | 1789 qident = (rn->query6[0] << 8) + rn->query6[1]; |
1532 | 1790 |
1533 break; | 1791 break; |
1534 #endif | 1792 #endif |
1535 | 1793 |
1536 default: /* NGX_RESOLVE_A */ | 1794 default: /* NGX_RESOLVE_A */ |
1537 | 1795 |
1538 if (rn->query == NULL || rn->naddrs != (u_short) -1) { | 1796 if (rn->query == NULL || rn->naddrs != (u_short) -1) { |
1539 ngx_log_error(r->log_level, r->log, 0, | 1797 ngx_log_error(r->log_level, r->log, 0, |
1540 "unexpected response for %V", &name); | 1798 "unexpected response for %V", &name); |
1799 ngx_resolver_free(r, name.data); | |
1800 goto failed; | |
1801 } | |
1802 | |
1803 if (trunc && rn->tcp) { | |
1541 ngx_resolver_free(r, name.data); | 1804 ngx_resolver_free(r, name.data); |
1542 goto failed; | 1805 goto failed; |
1543 } | 1806 } |
1544 | 1807 |
1545 qident = (rn->query[0] << 8) + rn->query[1]; | 1808 qident = (rn->query[0] << 8) + rn->query[1]; |
1552 ngx_resolver_free(r, name.data); | 1815 ngx_resolver_free(r, name.data); |
1553 goto failed; | 1816 goto failed; |
1554 } | 1817 } |
1555 | 1818 |
1556 ngx_resolver_free(r, name.data); | 1819 ngx_resolver_free(r, name.data); |
1820 | |
1821 if (trunc) { | |
1822 | |
1823 ngx_queue_remove(&rn->queue); | |
1824 | |
1825 if (rn->waiting == NULL) { | |
1826 ngx_rbtree_delete(&r->name_rbtree, &rn->node); | |
1827 ngx_resolver_free_node(r, rn); | |
1828 goto next; | |
1829 } | |
1830 | |
1831 rec = r->connections.elts; | |
1832 rec = &rec[rn->last_connection]; | |
1833 | |
1834 switch (qtype) { | |
1835 | |
1836 #if (NGX_HAVE_INET6) | |
1837 case NGX_RESOLVE_AAAA: | |
1838 | |
1839 rn->tcp6 = 1; | |
1840 | |
1841 (void) ngx_resolver_send_tcp_query(r, rec, rn->query6, rn->qlen); | |
1842 | |
1843 break; | |
1844 #endif | |
1845 | |
1846 default: /* NGX_RESOLVE_A */ | |
1847 | |
1848 rn->tcp = 1; | |
1849 | |
1850 (void) ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen); | |
1851 } | |
1852 | |
1853 rn->expire = ngx_time() + r->resend_timeout; | |
1854 | |
1855 ngx_queue_insert_head(&r->name_resend_queue, &rn->queue); | |
1856 | |
1857 goto next; | |
1858 } | |
1557 | 1859 |
1558 if (code == 0 && rn->code) { | 1860 if (code == 0 && rn->code) { |
1559 code = rn->code; | 1861 code = rn->code; |
1560 } | 1862 } |
1561 | 1863 |
3184 ngx_close_connection(c); | 3486 ngx_close_connection(c); |
3185 rec->udp = NULL; | 3487 rec->udp = NULL; |
3186 | 3488 |
3187 return NGX_ERROR; | 3489 return NGX_ERROR; |
3188 } | 3490 } |
3491 | |
3492 | |
3493 ngx_int_t | |
3494 ngx_tcp_connect(ngx_resolver_connection_t *rec) | |
3495 { | |
3496 int rc; | |
3497 ngx_int_t event; | |
3498 ngx_err_t err; | |
3499 ngx_uint_t level; | |
3500 ngx_socket_t s; | |
3501 ngx_event_t *rev, *wev; | |
3502 ngx_connection_t *c; | |
3503 | |
3504 s = ngx_socket(rec->sockaddr->sa_family, SOCK_STREAM, 0); | |
3505 | |
3506 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "TCP socket %d", s); | |
3507 | |
3508 if (s == (ngx_socket_t) -1) { | |
3509 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno, | |
3510 ngx_socket_n " failed"); | |
3511 return NGX_ERROR; | |
3512 } | |
3513 | |
3514 c = ngx_get_connection(s, &rec->log); | |
3515 | |
3516 if (c == NULL) { | |
3517 if (ngx_close_socket(s) == -1) { | |
3518 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno, | |
3519 ngx_close_socket_n "failed"); | |
3520 } | |
3521 | |
3522 return NGX_ERROR; | |
3523 } | |
3524 | |
3525 if (ngx_nonblocking(s) == -1) { | |
3526 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno, | |
3527 ngx_nonblocking_n " failed"); | |
3528 | |
3529 goto failed; | |
3530 } | |
3531 | |
3532 rev = c->read; | |
3533 wev = c->write; | |
3534 | |
3535 rev->log = &rec->log; | |
3536 wev->log = &rec->log; | |
3537 | |
3538 rec->tcp = c; | |
3539 | |
3540 c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); | |
3541 | |
3542 if (ngx_add_conn) { | |
3543 if (ngx_add_conn(c) == NGX_ERROR) { | |
3544 goto failed; | |
3545 } | |
3546 } | |
3547 | |
3548 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &rec->log, 0, | |
3549 "connect to %V, fd:%d #%uA", &rec->server, s, c->number); | |
3550 | |
3551 rc = connect(s, rec->sockaddr, rec->socklen); | |
3552 | |
3553 if (rc == -1) { | |
3554 err = ngx_socket_errno; | |
3555 | |
3556 | |
3557 if (err != NGX_EINPROGRESS | |
3558 #if (NGX_WIN32) | |
3559 /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */ | |
3560 && err != NGX_EAGAIN | |
3561 #endif | |
3562 ) | |
3563 { | |
3564 if (err == NGX_ECONNREFUSED | |
3565 #if (NGX_LINUX) | |
3566 /* | |
3567 * Linux returns EAGAIN instead of ECONNREFUSED | |
3568 * for unix sockets if listen queue is full | |
3569 */ | |
3570 || err == NGX_EAGAIN | |
3571 #endif | |
3572 || err == NGX_ECONNRESET | |
3573 || err == NGX_ENETDOWN | |
3574 || err == NGX_ENETUNREACH | |
3575 || err == NGX_EHOSTDOWN | |
3576 || err == NGX_EHOSTUNREACH) | |
3577 { | |
3578 level = NGX_LOG_ERR; | |
3579 | |
3580 } else { | |
3581 level = NGX_LOG_CRIT; | |
3582 } | |
3583 | |
3584 ngx_log_error(level, c->log, err, "connect() to %V failed", | |
3585 &rec->server); | |
3586 | |
3587 ngx_close_connection(c); | |
3588 rec->tcp = NULL; | |
3589 | |
3590 return NGX_ERROR; | |
3591 } | |
3592 } | |
3593 | |
3594 if (ngx_add_conn) { | |
3595 if (rc == -1) { | |
3596 | |
3597 /* NGX_EINPROGRESS */ | |
3598 | |
3599 return NGX_AGAIN; | |
3600 } | |
3601 | |
3602 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "connected"); | |
3603 | |
3604 wev->ready = 1; | |
3605 | |
3606 return NGX_OK; | |
3607 } | |
3608 | |
3609 if (ngx_event_flags & NGX_USE_IOCP_EVENT) { | |
3610 | |
3611 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, ngx_socket_errno, | |
3612 "connect(): %d", rc); | |
3613 | |
3614 if (ngx_blocking(s) == -1) { | |
3615 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno, | |
3616 ngx_blocking_n " failed"); | |
3617 goto failed; | |
3618 } | |
3619 | |
3620 /* | |
3621 * FreeBSD's aio allows to post an operation on non-connected socket. | |
3622 * NT does not support it. | |
3623 * | |
3624 * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT | |
3625 */ | |
3626 | |
3627 rev->ready = 1; | |
3628 wev->ready = 1; | |
3629 | |
3630 return NGX_OK; | |
3631 } | |
3632 | |
3633 if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { | |
3634 | |
3635 /* kqueue */ | |
3636 | |
3637 event = NGX_CLEAR_EVENT; | |
3638 | |
3639 } else { | |
3640 | |
3641 /* select, poll, /dev/poll */ | |
3642 | |
3643 event = NGX_LEVEL_EVENT; | |
3644 } | |
3645 | |
3646 if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { | |
3647 goto failed; | |
3648 } | |
3649 | |
3650 if (rc == -1) { | |
3651 | |
3652 /* NGX_EINPROGRESS */ | |
3653 | |
3654 if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) { | |
3655 goto failed; | |
3656 } | |
3657 | |
3658 return NGX_AGAIN; | |
3659 } | |
3660 | |
3661 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "connected"); | |
3662 | |
3663 wev->ready = 1; | |
3664 | |
3665 return NGX_OK; | |
3666 | |
3667 failed: | |
3668 | |
3669 ngx_close_connection(c); | |
3670 rec->tcp = NULL; | |
3671 | |
3672 return NGX_ERROR; | |
3673 } |