nxt_sockaddr.c (2154:68987edde84a) nxt_sockaddr.c (2175:e83cff38d672)
1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7#include <nxt_main.h>
8
9
10#if (NXT_INET6)
11static u_char *nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end);
12#endif
13
14static nxt_sockaddr_t *nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr);
15static nxt_sockaddr_t *nxt_sockaddr_inet6_parse(nxt_mp_t *mp, nxt_str_t *addr);
16static nxt_sockaddr_t *nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr);
17
1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7#include <nxt_main.h>
8
9
10#if (NXT_INET6)
11static u_char *nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end);
12#endif
13
14static nxt_sockaddr_t *nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr);
15static nxt_sockaddr_t *nxt_sockaddr_inet6_parse(nxt_mp_t *mp, nxt_str_t *addr);
16static nxt_sockaddr_t *nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr);
17
18static nxt_int_t nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs);
19static nxt_int_t nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs);
20static nxt_int_t nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs);
21
18
22
23nxt_sockaddr_t *
24nxt_sockaddr_cache_alloc(nxt_event_engine_t *engine, nxt_listen_socket_t *ls)
25{
26 size_t size;
27 uint8_t hint;
28 nxt_sockaddr_t *sa;
29
30 hint = NXT_EVENT_ENGINE_NO_MEM_HINT;

--- 397 unchanged lines hidden (view full) ---

428 return 0;
429 }
430
431 return 1;
432 }
433}
434
435
19nxt_sockaddr_t *
20nxt_sockaddr_cache_alloc(nxt_event_engine_t *engine, nxt_listen_socket_t *ls)
21{
22 size_t size;
23 uint8_t hint;
24 nxt_sockaddr_t *sa;
25
26 hint = NXT_EVENT_ENGINE_NO_MEM_HINT;

--- 397 unchanged lines hidden (view full) ---

424 return 0;
425 }
426
427 return 1;
428 }
429}
430
431
436size_t
437nxt_sockaddr_ntop(nxt_sockaddr_t *sa, u_char *buf, u_char *end, nxt_bool_t port)
438{
439 u_char *p;
440
441 switch (sa->u.sockaddr.sa_family) {
442
443 case AF_INET:
444 p = (u_char *) &sa->u.sockaddr_in.sin_addr;
445
446 if (port) {
447 p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud:%d",
448 p[0], p[1], p[2], p[3],
449 ntohs(sa->u.sockaddr_in.sin_port));
450 } else {
451 p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud",
452 p[0], p[1], p[2], p[3]);
453 }
454
455 return p - buf;
456
457#if (NXT_INET6)
458
432#if (NXT_INET6)
433
459 case AF_INET6:
460 p = buf;
461
462 if (port) {
463 *p++ = '[';
464 }
465
466 p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end);
467
468 if (port) {
469 p = nxt_sprintf(p, end, "]:%d",
470 ntohs(sa->u.sockaddr_in6.sin6_port));
471 }
472
473 return p - buf;
474#endif
475
476#if (NXT_HAVE_UNIX_DOMAIN)
477
478 case AF_UNIX:
479
480#if (NXT_LINUX)
481
482 p = (u_char *) sa->u.sockaddr_un.sun_path;
483
484 if (p[0] == '\0') {
485 size_t length;
486
487 /* Linux abstract socket address has no trailing zero. */
488
489 length = sa->socklen - offsetof(struct sockaddr_un, sun_path) - 1;
490 p = nxt_sprintf(buf, end, "unix:\\0%*s", length, p + 1);
491
492 } else {
493 p = nxt_sprintf(buf, end, "unix:%s", p);
494 }
495
496#else /* !(NXT_LINUX) */
497
498 p = nxt_sprintf(buf, end, "unix:%s", sa->u.sockaddr_un.sun_path);
499
500#endif
501
502 return p - buf;
503
504#endif /* NXT_HAVE_UNIX_DOMAIN */
505
506 default:
507 return 0;
508 }
509}
510
511
512#if (NXT_INET6)
513
514static u_char *
515nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end)
516{
517 u_char *p;
518 size_t zero_groups, last_zero_groups, ipv6_bytes;
519 nxt_uint_t i, zero_start, last_zero_start;
520
521 const size_t max_inet6_length =

--- 322 unchanged lines hidden (view full) ---

844 sa->u.sockaddr_in.sin_family = AF_INET;
845 sa->u.sockaddr_in.sin_addr.s_addr = inaddr;
846 sa->u.sockaddr_in.sin_port = htons((in_port_t) port);
847
848 return sa;
849}
850
851
434static u_char *
435nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end)
436{
437 u_char *p;
438 size_t zero_groups, last_zero_groups, ipv6_bytes;
439 nxt_uint_t i, zero_start, last_zero_start;
440
441 const size_t max_inet6_length =

--- 322 unchanged lines hidden (view full) ---

764 sa->u.sockaddr_in.sin_family = AF_INET;
765 sa->u.sockaddr_in.sin_addr.s_addr = inaddr;
766 sa->u.sockaddr_in.sin_port = htons((in_port_t) port);
767
768 return sa;
769}
770
771
852void
853nxt_job_sockaddr_parse(nxt_job_sockaddr_parse_t *jbs)
854{
855 u_char *p;
856 size_t length;
857 nxt_int_t ret;
858 nxt_work_handler_t handler;
859
860 nxt_job_set_name(&jbs->resolve.job, "job sockaddr parse");
861
862 length = jbs->addr.length;
863 p = jbs->addr.start;
864
865 if (length > 6 && nxt_memcmp(p, "unix:", 5) == 0) {
866 ret = nxt_job_sockaddr_unix_parse(jbs);
867
868 } else if (length != 0 && *p == '[') {
869 ret = nxt_job_sockaddr_inet6_parse(jbs);
870
871 } else {
872 ret = nxt_job_sockaddr_inet_parse(jbs);
873 }
874
875 switch (ret) {
876
877 case NXT_OK:
878 handler = jbs->resolve.ready_handler;
879 break;
880
881 case NXT_ERROR:
882 handler = jbs->resolve.error_handler;
883 break;
884
885 default: /* NXT_AGAIN */
886 return;
887 }
888
889 nxt_job_return(jbs->resolve.job.task, &jbs->resolve.job, handler);
890}
891
892
893static nxt_int_t
894nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs)
895{
896#if (NXT_HAVE_UNIX_DOMAIN)
897 size_t length, socklen;
898 u_char *path;
899 nxt_mp_t *mp;
900 nxt_sockaddr_t *sa;
901
902 /*
903 * Actual sockaddr_un length can be lesser or even larger than defined
904 * struct sockaddr_un length (see comment in nxt_socket.h). So
905 * limit maximum Unix domain socket address length by defined sun_path[]
906 * length because some OSes accept addresses twice larger than defined
907 * struct sockaddr_un. Also reserve space for a trailing zero to avoid
908 * ambiguity, since many OSes accept Unix domain socket addresses
909 * without a trailing zero.
910 */
911 const size_t max_len = sizeof(struct sockaddr_un)
912 - offsetof(struct sockaddr_un, sun_path) - 1;
913
914 /* cutting "unix:" */
915 length = jbs->addr.length - 5;
916 path = jbs->addr.start + 5;
917
918 if (length > max_len) {
919 nxt_thread_log_error(jbs->resolve.log_level,
920 "unix domain socket \"%V\" name is too long",
921 &jbs->addr);
922 return NXT_ERROR;
923 }
924
925 socklen = offsetof(struct sockaddr_un, sun_path) + length + 1;
926
927#if (NXT_LINUX)
928
929 /*
930 * Linux unix(7):
931 *
932 * abstract: an abstract socket address is distinguished by the fact
933 * that sun_path[0] is a null byte ('\0'). The socket's address in
934 * this namespace is given by the additional bytes in sun_path that
935 * are covered by the specified length of the address structure.
936 * (Null bytes in the name have no special significance.)
937 */
938 if (path[0] == '\0') {
939 socklen--;
940 }
941
942#endif
943
944 mp = jbs->resolve.job.mem_pool;
945
946 jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *));
947
948 if (nxt_fast_path(jbs->resolve.sockaddrs != NULL)) {
949 sa = nxt_sockaddr_alloc(mp, socklen, jbs->addr.length);
950
951 if (nxt_fast_path(sa != NULL)) {
952 jbs->resolve.count = 1;
953 jbs->resolve.sockaddrs[0] = sa;
954
955 sa->u.sockaddr_un.sun_family = AF_UNIX;
956 nxt_memcpy(sa->u.sockaddr_un.sun_path, path, length);
957
958 return NXT_OK;
959 }
960 }
961
962 return NXT_ERROR;
963
964#else /* !(NXT_HAVE_UNIX_DOMAIN) */
965
966 nxt_thread_log_error(jbs->resolve.log_level,
967 "unix domain socket \"%V\" is not supported",
968 &jbs->addr);
969 return NXT_ERROR;
970
971#endif
972}
973
974
975static nxt_int_t
976nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs)
977{
978#if (NXT_INET6)
979 u_char *p, *addr, *addr_end;
980 size_t length;
981 nxt_mp_t *mp;
982 nxt_int_t port;
983 nxt_sockaddr_t *sa;
984 struct in6_addr *in6_addr;
985
986 length = jbs->addr.length - 1;
987 addr = jbs->addr.start + 1;
988
989 addr_end = nxt_memchr(addr, ']', length);
990
991 if (addr_end == NULL) {
992 goto invalid_address;
993 }
994
995 mp = jbs->resolve.job.mem_pool;
996
997 jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *));
998
999 if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) {
1000 return NXT_ERROR;
1001 }
1002
1003 sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6),
1004 NXT_INET6_ADDR_STR_LEN);
1005
1006 if (nxt_slow_path(sa == NULL)) {
1007 return NXT_ERROR;
1008 }
1009
1010 jbs->resolve.count = 1;
1011 jbs->resolve.sockaddrs[0] = sa;
1012
1013 in6_addr = &sa->u.sockaddr_in6.sin6_addr;
1014
1015 if (nxt_inet6_addr(in6_addr, addr, addr_end - addr) != NXT_OK) {
1016 goto invalid_address;
1017 }
1018
1019 p = addr_end + 1;
1020 length = (addr + length) - p;
1021
1022 if (length == 0) {
1023 jbs->no_port = 1;
1024 port = jbs->resolve.port;
1025 goto found;
1026 }
1027
1028 if (*p == ':') {
1029 port = nxt_int_parse(p + 1, length - 1);
1030
1031 if (port >= 1 && port <= 65535) {
1032 port = htons((in_port_t) port);
1033 goto found;
1034 }
1035 }
1036
1037 nxt_thread_log_error(jbs->resolve.log_level,
1038 "invalid port in \"%V\"", &jbs->addr);
1039
1040 return NXT_ERROR;
1041
1042found:
1043
1044 sa->u.sockaddr_in6.sin6_family = AF_INET6;
1045 sa->u.sockaddr_in6.sin6_port = (in_port_t) port;
1046
1047 if (IN6_IS_ADDR_UNSPECIFIED(in6_addr)) {
1048 jbs->wildcard = 1;
1049 }
1050
1051 return NXT_OK;
1052
1053invalid_address:
1054
1055 nxt_thread_log_error(jbs->resolve.log_level,
1056 "invalid IPv6 address in \"%V\"", &jbs->addr);
1057 return NXT_ERROR;
1058
1059#else
1060
1061 nxt_thread_log_error(jbs->resolve.log_level,
1062 "IPv6 socket \"%V\" is not supported", &jbs->addr);
1063 return NXT_ERROR;
1064
1065#endif
1066}
1067
1068
1069static nxt_int_t
1070nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs)
1071{
1072 u_char *p, *host;
1073 size_t length;
1074 nxt_mp_t *mp;
1075 nxt_int_t port;
1076 in_addr_t addr;
1077 nxt_sockaddr_t *sa;
1078
1079 addr = INADDR_ANY;
1080
1081 length = jbs->addr.length;
1082 host = jbs->addr.start;
1083
1084 p = nxt_memchr(host, ':', length);
1085
1086 if (p == NULL) {
1087
1088 /* single value port, address, or host name */
1089
1090 port = nxt_int_parse(host, length);
1091
1092 if (port > 0) {
1093 if (port > 65535) {
1094 goto invalid_port;
1095 }
1096
1097 /* "*:XX" */
1098 port = htons((in_port_t) port);
1099 jbs->resolve.port = (in_port_t) port;
1100
1101 } else {
1102 jbs->no_port = 1;
1103
1104 addr = nxt_inet_addr(host, length);
1105
1106 if (addr == INADDR_NONE) {
1107 jbs->resolve.name.length = length;
1108 jbs->resolve.name.start = host;
1109
1110 nxt_job_resolve(&jbs->resolve);
1111 return NXT_AGAIN;
1112 }
1113
1114 /* "x.x.x.x" */
1115 port = jbs->resolve.port;
1116 }
1117
1118 } else {
1119
1120 /* x.x.x.x:XX or host:XX */
1121
1122 p++;
1123 length = (host + length) - p;
1124 port = nxt_int_parse(p, length);
1125
1126 if (port < 1 || port > 65535) {
1127 goto invalid_port;
1128 }
1129
1130 port = htons((in_port_t) port);
1131
1132 length = (p - 1) - host;
1133
1134 if (length != 1 || host[0] != '*') {
1135 addr = nxt_inet_addr(host, length);
1136
1137 if (addr == INADDR_NONE) {
1138 jbs->resolve.name.length = length;
1139 jbs->resolve.name.start = host;
1140 jbs->resolve.port = (in_port_t) port;
1141
1142 nxt_job_resolve(&jbs->resolve);
1143 return NXT_AGAIN;
1144 }
1145
1146 /* "x.x.x.x:XX" */
1147 }
1148 }
1149
1150 mp = jbs->resolve.job.mem_pool;
1151
1152 jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *));
1153 if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) {
1154 return NXT_ERROR;
1155 }
1156
1157 sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in),
1158 NXT_INET_ADDR_STR_LEN);
1159
1160 if (nxt_fast_path(sa != NULL)) {
1161 jbs->resolve.count = 1;
1162 jbs->resolve.sockaddrs[0] = sa;
1163
1164 jbs->wildcard = (addr == INADDR_ANY);
1165
1166 sa->u.sockaddr_in.sin_family = AF_INET;
1167 sa->u.sockaddr_in.sin_port = (in_port_t) port;
1168 sa->u.sockaddr_in.sin_addr.s_addr = addr;
1169
1170 return NXT_OK;
1171 }
1172
1173 return NXT_ERROR;
1174
1175invalid_port:
1176
1177 nxt_thread_log_error(jbs->resolve.log_level,
1178 "invalid port in \"%V\"", &jbs->addr);
1179
1180 return NXT_ERROR;
1181}
1182
1183
1184in_addr_t
1185nxt_inet_addr(u_char *buf, size_t length)
1186{
1187 u_char c, *end;
1188 in_addr_t addr;
1189 nxt_uint_t digit, octet, dots;
1190
1191 if (nxt_slow_path(*(buf + length - 1) == '.')) {

--- 195 unchanged lines hidden ---
772in_addr_t
773nxt_inet_addr(u_char *buf, size_t length)
774{
775 u_char c, *end;
776 in_addr_t addr;
777 nxt_uint_t digit, octet, dots;
778
779 if (nxt_slow_path(*(buf + length - 1) == '.')) {

--- 195 unchanged lines hidden ---