1*0Sigor@sysoev.ru 2*0Sigor@sysoev.ru /* 3*0Sigor@sysoev.ru * Copyright (C) Igor Sysoev 4*0Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 5*0Sigor@sysoev.ru */ 6*0Sigor@sysoev.ru 7*0Sigor@sysoev.ru #include <nxt_main.h> 8*0Sigor@sysoev.ru 9*0Sigor@sysoev.ru 10*0Sigor@sysoev.ru #if (NXT_INET6) 11*0Sigor@sysoev.ru static u_char *nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end); 12*0Sigor@sysoev.ru #endif 13*0Sigor@sysoev.ru 14*0Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs); 15*0Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs); 16*0Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs); 17*0Sigor@sysoev.ru 18*0Sigor@sysoev.ru 19*0Sigor@sysoev.ru nxt_sockaddr_t * 20*0Sigor@sysoev.ru nxt_sockaddr_alloc(nxt_mem_pool_t *mp, socklen_t len) 21*0Sigor@sysoev.ru { 22*0Sigor@sysoev.ru nxt_sockaddr_t *sa; 23*0Sigor@sysoev.ru 24*0Sigor@sysoev.ru /* 25*0Sigor@sysoev.ru * The current struct sockaddr's define 32-bit fields at maximum 26*0Sigor@sysoev.ru * and may define 64-bit AF_INET6 fields in the future. Alignment 27*0Sigor@sysoev.ru * of memory allocated by nxt_mem_zalloc() is enough for these fields. 28*0Sigor@sysoev.ru * If 128-bit alignment will be required then nxt_mem_malloc() and 29*0Sigor@sysoev.ru * nxt_memzero() should be used instead. 30*0Sigor@sysoev.ru */ 31*0Sigor@sysoev.ru sa = nxt_mem_zalloc(mp, offsetof(nxt_sockaddr_t, u) + len); 32*0Sigor@sysoev.ru 33*0Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 34*0Sigor@sysoev.ru nxt_socklen_set(sa, len); 35*0Sigor@sysoev.ru } 36*0Sigor@sysoev.ru 37*0Sigor@sysoev.ru return sa; 38*0Sigor@sysoev.ru } 39*0Sigor@sysoev.ru 40*0Sigor@sysoev.ru 41*0Sigor@sysoev.ru nxt_sockaddr_t * 42*0Sigor@sysoev.ru nxt_sockaddr_create(nxt_mem_pool_t *mp, struct sockaddr *sockaddr, 43*0Sigor@sysoev.ru socklen_t len) 44*0Sigor@sysoev.ru { 45*0Sigor@sysoev.ru size_t size, copy; 46*0Sigor@sysoev.ru nxt_sockaddr_t *sa; 47*0Sigor@sysoev.ru 48*0Sigor@sysoev.ru size = len; 49*0Sigor@sysoev.ru copy = len; 50*0Sigor@sysoev.ru 51*0Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 52*0Sigor@sysoev.ru 53*0Sigor@sysoev.ru /* 54*0Sigor@sysoev.ru * Unspecified Unix domain sockaddr_un form and length are very 55*0Sigor@sysoev.ru * platform depended (see comment in unix/socket.h). Here they are 56*0Sigor@sysoev.ru * normalized to the sockaddr_un with single zero byte sun_path[]. 57*0Sigor@sysoev.ru */ 58*0Sigor@sysoev.ru 59*0Sigor@sysoev.ru if (size <= offsetof(struct sockaddr_un, sun_path)) { 60*0Sigor@sysoev.ru /* 61*0Sigor@sysoev.ru * Small socket length means a short unspecified Unix domain 62*0Sigor@sysoev.ru * socket address: 63*0Sigor@sysoev.ru * 64*0Sigor@sysoev.ru * getsockname() and getpeername() on OpenBSD prior to 5.3 65*0Sigor@sysoev.ru * return zero length and does not update a passed sockaddr 66*0Sigor@sysoev.ru * buffer at all. 67*0Sigor@sysoev.ru * 68*0Sigor@sysoev.ru * Linux returns length equal to 2, i.e. sockaddr_un without 69*0Sigor@sysoev.ru * sun_path[], unix(7): 70*0Sigor@sysoev.ru * 71*0Sigor@sysoev.ru * unnamed: A stream socket that has not been bound 72*0Sigor@sysoev.ru * to a pathname using bind(2) has no name. Likewise, 73*0Sigor@sysoev.ru * the two sockets created by socketpair(2) are unnamed. 74*0Sigor@sysoev.ru * When the address of an unnamed socket is returned by 75*0Sigor@sysoev.ru * getsockname(2), getpeername(2), and accept(2), its 76*0Sigor@sysoev.ru * length is sizeof(sa_family_t), and sun_path should 77*0Sigor@sysoev.ru * not be inspected. 78*0Sigor@sysoev.ru */ 79*0Sigor@sysoev.ru size = offsetof(struct sockaddr_un, sun_path) + 1; 80*0Sigor@sysoev.ru 81*0Sigor@sysoev.ru #if !(NXT_LINUX) 82*0Sigor@sysoev.ru 83*0Sigor@sysoev.ru } else if (sockaddr->sa_family == AF_UNIX && sockaddr->sa_data[0] == '\0') { 84*0Sigor@sysoev.ru /* 85*0Sigor@sysoev.ru * Omit nonsignificant zeros of the unspecified Unix domain socket 86*0Sigor@sysoev.ru * address. This test is disabled for Linux since Linux abstract 87*0Sigor@sysoev.ru * socket address also starts with zero. However Linux unspecified 88*0Sigor@sysoev.ru * Unix domain socket address is short and is handled above. 89*0Sigor@sysoev.ru */ 90*0Sigor@sysoev.ru size = offsetof(struct sockaddr_un, sun_path) + 1; 91*0Sigor@sysoev.ru copy = size; 92*0Sigor@sysoev.ru 93*0Sigor@sysoev.ru #endif 94*0Sigor@sysoev.ru } 95*0Sigor@sysoev.ru 96*0Sigor@sysoev.ru #endif /* NXT_HAVE_UNIX_DOMAIN */ 97*0Sigor@sysoev.ru 98*0Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, size); 99*0Sigor@sysoev.ru 100*0Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 101*0Sigor@sysoev.ru 102*0Sigor@sysoev.ru nxt_memcpy(&sa->u.sockaddr, sockaddr, copy); 103*0Sigor@sysoev.ru 104*0Sigor@sysoev.ru #if (NXT_SOCKADDR_SA_LEN) 105*0Sigor@sysoev.ru 106*0Sigor@sysoev.ru /* Update shortcut sockaddr length overwritten by nxt_memcpy(). */ 107*0Sigor@sysoev.ru nxt_socklen_set(sa, size); 108*0Sigor@sysoev.ru 109*0Sigor@sysoev.ru #endif 110*0Sigor@sysoev.ru 111*0Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN && NXT_OPENBSD) 112*0Sigor@sysoev.ru 113*0Sigor@sysoev.ru if (len == 0) { 114*0Sigor@sysoev.ru sa->u.sockaddr.sa_family = AF_UNIX; 115*0Sigor@sysoev.ru } 116*0Sigor@sysoev.ru 117*0Sigor@sysoev.ru #endif 118*0Sigor@sysoev.ru } 119*0Sigor@sysoev.ru 120*0Sigor@sysoev.ru return sa; 121*0Sigor@sysoev.ru } 122*0Sigor@sysoev.ru 123*0Sigor@sysoev.ru 124*0Sigor@sysoev.ru nxt_sockaddr_t * 125*0Sigor@sysoev.ru nxt_sockaddr_copy(nxt_mem_pool_t *mp, nxt_sockaddr_t *src) 126*0Sigor@sysoev.ru { 127*0Sigor@sysoev.ru size_t len; 128*0Sigor@sysoev.ru nxt_sockaddr_t *dst; 129*0Sigor@sysoev.ru 130*0Sigor@sysoev.ru len = offsetof(nxt_sockaddr_t, u) + nxt_socklen(src); 131*0Sigor@sysoev.ru 132*0Sigor@sysoev.ru dst = nxt_mem_alloc(mp, len); 133*0Sigor@sysoev.ru 134*0Sigor@sysoev.ru if (nxt_fast_path(dst != NULL)) { 135*0Sigor@sysoev.ru nxt_memcpy(dst, src, len); 136*0Sigor@sysoev.ru } 137*0Sigor@sysoev.ru 138*0Sigor@sysoev.ru return dst; 139*0Sigor@sysoev.ru } 140*0Sigor@sysoev.ru 141*0Sigor@sysoev.ru 142*0Sigor@sysoev.ru nxt_sockaddr_t * 143*0Sigor@sysoev.ru nxt_getsockname(nxt_mem_pool_t *mp, nxt_socket_t s) 144*0Sigor@sysoev.ru { 145*0Sigor@sysoev.ru int ret; 146*0Sigor@sysoev.ru socklen_t socklen; 147*0Sigor@sysoev.ru nxt_sockaddr_buf_t sockaddr; 148*0Sigor@sysoev.ru 149*0Sigor@sysoev.ru socklen = NXT_SOCKADDR_LEN; 150*0Sigor@sysoev.ru 151*0Sigor@sysoev.ru ret = getsockname(s, &sockaddr.buf, &socklen); 152*0Sigor@sysoev.ru 153*0Sigor@sysoev.ru if (nxt_fast_path(ret == 0)) { 154*0Sigor@sysoev.ru return nxt_sockaddr_create(mp, &sockaddr.buf, socklen); 155*0Sigor@sysoev.ru } 156*0Sigor@sysoev.ru 157*0Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR, "getsockname(%d) failed %E", 158*0Sigor@sysoev.ru s, nxt_errno); 159*0Sigor@sysoev.ru 160*0Sigor@sysoev.ru return NULL; 161*0Sigor@sysoev.ru } 162*0Sigor@sysoev.ru 163*0Sigor@sysoev.ru 164*0Sigor@sysoev.ru nxt_int_t 165*0Sigor@sysoev.ru nxt_sockaddr_text(nxt_mem_pool_t *mp, nxt_sockaddr_t *sa, nxt_bool_t port) 166*0Sigor@sysoev.ru { 167*0Sigor@sysoev.ru size_t len; 168*0Sigor@sysoev.ru u_char *p; 169*0Sigor@sysoev.ru u_char buf[NXT_SOCKADDR_STR_LEN + NXT_SOCKPORT_STR_LEN]; 170*0Sigor@sysoev.ru 171*0Sigor@sysoev.ru len = NXT_SOCKADDR_STR_LEN + NXT_SOCKPORT_STR_LEN; 172*0Sigor@sysoev.ru 173*0Sigor@sysoev.ru len = nxt_sockaddr_ntop(sa, buf, buf + len, port); 174*0Sigor@sysoev.ru 175*0Sigor@sysoev.ru p = nxt_mem_alloc(mp, len); 176*0Sigor@sysoev.ru 177*0Sigor@sysoev.ru if (nxt_fast_path(p != NULL)) { 178*0Sigor@sysoev.ru 179*0Sigor@sysoev.ru sa->text = p; 180*0Sigor@sysoev.ru sa->text_len = len; 181*0Sigor@sysoev.ru nxt_memcpy(p, buf, len); 182*0Sigor@sysoev.ru 183*0Sigor@sysoev.ru return NXT_OK; 184*0Sigor@sysoev.ru } 185*0Sigor@sysoev.ru 186*0Sigor@sysoev.ru return NXT_ERROR; 187*0Sigor@sysoev.ru } 188*0Sigor@sysoev.ru 189*0Sigor@sysoev.ru 190*0Sigor@sysoev.ru uint32_t 191*0Sigor@sysoev.ru nxt_sockaddr_port(nxt_sockaddr_t *sa) 192*0Sigor@sysoev.ru { 193*0Sigor@sysoev.ru uint32_t port; 194*0Sigor@sysoev.ru 195*0Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 196*0Sigor@sysoev.ru 197*0Sigor@sysoev.ru #if (NXT_INET6) 198*0Sigor@sysoev.ru 199*0Sigor@sysoev.ru case AF_INET6: 200*0Sigor@sysoev.ru port = sa->u.sockaddr_in6.sin6_port; 201*0Sigor@sysoev.ru break; 202*0Sigor@sysoev.ru 203*0Sigor@sysoev.ru #endif 204*0Sigor@sysoev.ru 205*0Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 206*0Sigor@sysoev.ru 207*0Sigor@sysoev.ru case AF_UNIX: 208*0Sigor@sysoev.ru return 0; 209*0Sigor@sysoev.ru 210*0Sigor@sysoev.ru #endif 211*0Sigor@sysoev.ru 212*0Sigor@sysoev.ru default: 213*0Sigor@sysoev.ru port = sa->u.sockaddr_in.sin_port; 214*0Sigor@sysoev.ru break; 215*0Sigor@sysoev.ru } 216*0Sigor@sysoev.ru 217*0Sigor@sysoev.ru return ntohs((uint16_t) port); 218*0Sigor@sysoev.ru } 219*0Sigor@sysoev.ru 220*0Sigor@sysoev.ru 221*0Sigor@sysoev.ru nxt_bool_t 222*0Sigor@sysoev.ru nxt_sockaddr_cmp(nxt_sockaddr_t *sa1, nxt_sockaddr_t *sa2) 223*0Sigor@sysoev.ru { 224*0Sigor@sysoev.ru if (nxt_socklen(sa1) != nxt_socklen(sa2)) { 225*0Sigor@sysoev.ru return 0; 226*0Sigor@sysoev.ru } 227*0Sigor@sysoev.ru 228*0Sigor@sysoev.ru if (sa1->type != sa2->type) { 229*0Sigor@sysoev.ru return 0; 230*0Sigor@sysoev.ru } 231*0Sigor@sysoev.ru 232*0Sigor@sysoev.ru if (sa1->u.sockaddr.sa_family != sa2->u.sockaddr.sa_family) { 233*0Sigor@sysoev.ru return 0; 234*0Sigor@sysoev.ru } 235*0Sigor@sysoev.ru 236*0Sigor@sysoev.ru /* 237*0Sigor@sysoev.ru * sockaddr struct's cannot be compared in whole since kernel 238*0Sigor@sysoev.ru * may fill some fields in inherited sockaddr struct's. 239*0Sigor@sysoev.ru */ 240*0Sigor@sysoev.ru 241*0Sigor@sysoev.ru switch (sa1->u.sockaddr.sa_family) { 242*0Sigor@sysoev.ru 243*0Sigor@sysoev.ru #if (NXT_INET6) 244*0Sigor@sysoev.ru 245*0Sigor@sysoev.ru case AF_INET6: 246*0Sigor@sysoev.ru if (sa1->u.sockaddr_in6.sin6_port != sa2->u.sockaddr_in6.sin6_port) { 247*0Sigor@sysoev.ru return 0; 248*0Sigor@sysoev.ru } 249*0Sigor@sysoev.ru 250*0Sigor@sysoev.ru if (nxt_memcmp(&sa1->u.sockaddr_in6.sin6_addr, 251*0Sigor@sysoev.ru &sa2->u.sockaddr_in6.sin6_addr, 16) 252*0Sigor@sysoev.ru != 0) 253*0Sigor@sysoev.ru { 254*0Sigor@sysoev.ru return 0; 255*0Sigor@sysoev.ru } 256*0Sigor@sysoev.ru 257*0Sigor@sysoev.ru return 1; 258*0Sigor@sysoev.ru 259*0Sigor@sysoev.ru #endif 260*0Sigor@sysoev.ru 261*0Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 262*0Sigor@sysoev.ru 263*0Sigor@sysoev.ru case AF_UNIX: 264*0Sigor@sysoev.ru { 265*0Sigor@sysoev.ru size_t len; 266*0Sigor@sysoev.ru 267*0Sigor@sysoev.ru len = nxt_socklen(sa1) - offsetof(struct sockaddr_un, sun_path); 268*0Sigor@sysoev.ru 269*0Sigor@sysoev.ru if (nxt_memcmp(&sa1->u.sockaddr_un.sun_path, 270*0Sigor@sysoev.ru &sa2->u.sockaddr_un.sun_path, len) 271*0Sigor@sysoev.ru != 0) 272*0Sigor@sysoev.ru { 273*0Sigor@sysoev.ru return 0; 274*0Sigor@sysoev.ru } 275*0Sigor@sysoev.ru 276*0Sigor@sysoev.ru return 1; 277*0Sigor@sysoev.ru } 278*0Sigor@sysoev.ru 279*0Sigor@sysoev.ru #endif 280*0Sigor@sysoev.ru 281*0Sigor@sysoev.ru default: /* AF_INET */ 282*0Sigor@sysoev.ru if (sa1->u.sockaddr_in.sin_port != sa2->u.sockaddr_in.sin_port) { 283*0Sigor@sysoev.ru return 0; 284*0Sigor@sysoev.ru } 285*0Sigor@sysoev.ru 286*0Sigor@sysoev.ru if (sa1->u.sockaddr_in.sin_addr.s_addr 287*0Sigor@sysoev.ru != sa2->u.sockaddr_in.sin_addr.s_addr) 288*0Sigor@sysoev.ru { 289*0Sigor@sysoev.ru return 0; 290*0Sigor@sysoev.ru } 291*0Sigor@sysoev.ru 292*0Sigor@sysoev.ru return 1; 293*0Sigor@sysoev.ru } 294*0Sigor@sysoev.ru } 295*0Sigor@sysoev.ru 296*0Sigor@sysoev.ru 297*0Sigor@sysoev.ru size_t 298*0Sigor@sysoev.ru nxt_sockaddr_ntop(nxt_sockaddr_t *sa, u_char *buf, u_char *end, nxt_bool_t port) 299*0Sigor@sysoev.ru { 300*0Sigor@sysoev.ru u_char *p; 301*0Sigor@sysoev.ru 302*0Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 303*0Sigor@sysoev.ru 304*0Sigor@sysoev.ru case AF_INET: 305*0Sigor@sysoev.ru p = (u_char *) &sa->u.sockaddr_in.sin_addr; 306*0Sigor@sysoev.ru 307*0Sigor@sysoev.ru if (port) { 308*0Sigor@sysoev.ru p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud:%d", 309*0Sigor@sysoev.ru p[0], p[1], p[2], p[3], 310*0Sigor@sysoev.ru ntohs(sa->u.sockaddr_in.sin_port)); 311*0Sigor@sysoev.ru } else { 312*0Sigor@sysoev.ru p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud", 313*0Sigor@sysoev.ru p[0], p[1], p[2], p[3]); 314*0Sigor@sysoev.ru } 315*0Sigor@sysoev.ru 316*0Sigor@sysoev.ru return p - buf; 317*0Sigor@sysoev.ru 318*0Sigor@sysoev.ru #if (NXT_INET6) 319*0Sigor@sysoev.ru 320*0Sigor@sysoev.ru case AF_INET6: 321*0Sigor@sysoev.ru p = buf; 322*0Sigor@sysoev.ru 323*0Sigor@sysoev.ru if (port) { 324*0Sigor@sysoev.ru *p++ = '['; 325*0Sigor@sysoev.ru } 326*0Sigor@sysoev.ru 327*0Sigor@sysoev.ru p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end); 328*0Sigor@sysoev.ru 329*0Sigor@sysoev.ru if (port) { 330*0Sigor@sysoev.ru p = nxt_sprintf(p, end, "]:%d", 331*0Sigor@sysoev.ru ntohs(sa->u.sockaddr_in6.sin6_port)); 332*0Sigor@sysoev.ru } 333*0Sigor@sysoev.ru 334*0Sigor@sysoev.ru return p - buf; 335*0Sigor@sysoev.ru #endif 336*0Sigor@sysoev.ru 337*0Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 338*0Sigor@sysoev.ru 339*0Sigor@sysoev.ru case AF_UNIX: 340*0Sigor@sysoev.ru 341*0Sigor@sysoev.ru #if (NXT_LINUX) 342*0Sigor@sysoev.ru 343*0Sigor@sysoev.ru p = (u_char *) sa->u.sockaddr_un.sun_path; 344*0Sigor@sysoev.ru 345*0Sigor@sysoev.ru if (p[0] == '\0') { 346*0Sigor@sysoev.ru int len; 347*0Sigor@sysoev.ru 348*0Sigor@sysoev.ru /* Linux abstract socket address has no trailing zero. */ 349*0Sigor@sysoev.ru 350*0Sigor@sysoev.ru len = nxt_socklen(sa) - offsetof(struct sockaddr_un, sun_path) - 1; 351*0Sigor@sysoev.ru p = nxt_sprintf(buf, end, "unix:\\0%*s", len, p + 1); 352*0Sigor@sysoev.ru 353*0Sigor@sysoev.ru } else { 354*0Sigor@sysoev.ru p = nxt_sprintf(buf, end, "unix:%s", p); 355*0Sigor@sysoev.ru } 356*0Sigor@sysoev.ru 357*0Sigor@sysoev.ru #else /* !(NXT_LINUX) */ 358*0Sigor@sysoev.ru 359*0Sigor@sysoev.ru p = nxt_sprintf(buf, end, "unix:%s", sa->u.sockaddr_un.sun_path); 360*0Sigor@sysoev.ru 361*0Sigor@sysoev.ru #endif 362*0Sigor@sysoev.ru 363*0Sigor@sysoev.ru return p - buf; 364*0Sigor@sysoev.ru 365*0Sigor@sysoev.ru #endif /* NXT_HAVE_UNIX_DOMAIN */ 366*0Sigor@sysoev.ru 367*0Sigor@sysoev.ru default: 368*0Sigor@sysoev.ru return 0; 369*0Sigor@sysoev.ru } 370*0Sigor@sysoev.ru } 371*0Sigor@sysoev.ru 372*0Sigor@sysoev.ru 373*0Sigor@sysoev.ru #if (NXT_INET6) 374*0Sigor@sysoev.ru 375*0Sigor@sysoev.ru static u_char * 376*0Sigor@sysoev.ru nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end) 377*0Sigor@sysoev.ru { 378*0Sigor@sysoev.ru u_char *p; 379*0Sigor@sysoev.ru size_t zero_groups, last_zero_groups, ipv6_bytes; 380*0Sigor@sysoev.ru nxt_uint_t i, zero_start, last_zero_start; 381*0Sigor@sysoev.ru 382*0Sigor@sysoev.ru if (buf + NXT_INET6_ADDR_STR_LEN > end) { 383*0Sigor@sysoev.ru return buf; 384*0Sigor@sysoev.ru } 385*0Sigor@sysoev.ru 386*0Sigor@sysoev.ru zero_start = 8; 387*0Sigor@sysoev.ru zero_groups = 0; 388*0Sigor@sysoev.ru last_zero_start = 8; 389*0Sigor@sysoev.ru last_zero_groups = 0; 390*0Sigor@sysoev.ru 391*0Sigor@sysoev.ru for (i = 0; i < 16; i += 2) { 392*0Sigor@sysoev.ru 393*0Sigor@sysoev.ru if (addr[i] == 0 && addr[i + 1] == 0) { 394*0Sigor@sysoev.ru 395*0Sigor@sysoev.ru if (last_zero_groups == 0) { 396*0Sigor@sysoev.ru last_zero_start = i; 397*0Sigor@sysoev.ru } 398*0Sigor@sysoev.ru 399*0Sigor@sysoev.ru last_zero_groups++; 400*0Sigor@sysoev.ru 401*0Sigor@sysoev.ru } else { 402*0Sigor@sysoev.ru if (zero_groups < last_zero_groups) { 403*0Sigor@sysoev.ru zero_groups = last_zero_groups; 404*0Sigor@sysoev.ru zero_start = last_zero_start; 405*0Sigor@sysoev.ru } 406*0Sigor@sysoev.ru 407*0Sigor@sysoev.ru last_zero_groups = 0; 408*0Sigor@sysoev.ru } 409*0Sigor@sysoev.ru } 410*0Sigor@sysoev.ru 411*0Sigor@sysoev.ru if (zero_groups < last_zero_groups) { 412*0Sigor@sysoev.ru zero_groups = last_zero_groups; 413*0Sigor@sysoev.ru zero_start = last_zero_start; 414*0Sigor@sysoev.ru } 415*0Sigor@sysoev.ru 416*0Sigor@sysoev.ru ipv6_bytes = 16; 417*0Sigor@sysoev.ru p = buf; 418*0Sigor@sysoev.ru 419*0Sigor@sysoev.ru if (zero_start == 0) { 420*0Sigor@sysoev.ru 421*0Sigor@sysoev.ru /* IPv4-mapped address */ 422*0Sigor@sysoev.ru if ((zero_groups == 5 && addr[10] == 0xff && addr[11] == 0xff) 423*0Sigor@sysoev.ru /* IPv4-compatible address */ 424*0Sigor@sysoev.ru || (zero_groups == 6) 425*0Sigor@sysoev.ru /* not IPv6 loopback address */ 426*0Sigor@sysoev.ru || (zero_groups == 7 && addr[14] != 0 && addr[15] != 1)) 427*0Sigor@sysoev.ru { 428*0Sigor@sysoev.ru ipv6_bytes = 12; 429*0Sigor@sysoev.ru } 430*0Sigor@sysoev.ru 431*0Sigor@sysoev.ru *p++ = ':'; 432*0Sigor@sysoev.ru } 433*0Sigor@sysoev.ru 434*0Sigor@sysoev.ru for (i = 0; i < ipv6_bytes; i += 2) { 435*0Sigor@sysoev.ru 436*0Sigor@sysoev.ru if (i == zero_start) { 437*0Sigor@sysoev.ru /* Output maximum number of consecutive zero groups as "::". */ 438*0Sigor@sysoev.ru i += (zero_groups - 1) * 2; 439*0Sigor@sysoev.ru *p++ = ':'; 440*0Sigor@sysoev.ru continue; 441*0Sigor@sysoev.ru } 442*0Sigor@sysoev.ru 443*0Sigor@sysoev.ru p = nxt_sprintf(p, end, "%uxd", (addr[i] << 8) + addr[i + 1]); 444*0Sigor@sysoev.ru 445*0Sigor@sysoev.ru if (i < 14) { 446*0Sigor@sysoev.ru *p++ = ':'; 447*0Sigor@sysoev.ru } 448*0Sigor@sysoev.ru } 449*0Sigor@sysoev.ru 450*0Sigor@sysoev.ru if (ipv6_bytes == 12) { 451*0Sigor@sysoev.ru p = nxt_sprintf(p, end, "%ud.%ud.%ud.%ud", 452*0Sigor@sysoev.ru addr[12], addr[13], addr[14], addr[15]); 453*0Sigor@sysoev.ru } 454*0Sigor@sysoev.ru 455*0Sigor@sysoev.ru return p; 456*0Sigor@sysoev.ru } 457*0Sigor@sysoev.ru 458*0Sigor@sysoev.ru #endif 459*0Sigor@sysoev.ru 460*0Sigor@sysoev.ru 461*0Sigor@sysoev.ru void 462*0Sigor@sysoev.ru nxt_job_sockaddr_parse(nxt_job_sockaddr_parse_t *jbs) 463*0Sigor@sysoev.ru { 464*0Sigor@sysoev.ru u_char *p; 465*0Sigor@sysoev.ru size_t len; 466*0Sigor@sysoev.ru nxt_int_t ret; 467*0Sigor@sysoev.ru nxt_work_handler_t handler; 468*0Sigor@sysoev.ru 469*0Sigor@sysoev.ru nxt_job_set_name(&jbs->resolve.job, "job sockaddr parse"); 470*0Sigor@sysoev.ru 471*0Sigor@sysoev.ru len = jbs->addr.len; 472*0Sigor@sysoev.ru p = jbs->addr.data; 473*0Sigor@sysoev.ru 474*0Sigor@sysoev.ru if (len > 6 && nxt_memcmp(p, (u_char *) "unix:", 5) == 0) { 475*0Sigor@sysoev.ru ret = nxt_job_sockaddr_unix_parse(jbs); 476*0Sigor@sysoev.ru 477*0Sigor@sysoev.ru } else if (len != 0 && *p == '[') { 478*0Sigor@sysoev.ru ret = nxt_job_sockaddr_inet6_parse(jbs); 479*0Sigor@sysoev.ru 480*0Sigor@sysoev.ru } else { 481*0Sigor@sysoev.ru ret = nxt_job_sockaddr_inet_parse(jbs); 482*0Sigor@sysoev.ru } 483*0Sigor@sysoev.ru 484*0Sigor@sysoev.ru switch (ret) { 485*0Sigor@sysoev.ru 486*0Sigor@sysoev.ru case NXT_OK: 487*0Sigor@sysoev.ru handler = jbs->resolve.ready_handler; 488*0Sigor@sysoev.ru break; 489*0Sigor@sysoev.ru 490*0Sigor@sysoev.ru case NXT_ERROR: 491*0Sigor@sysoev.ru handler = jbs->resolve.error_handler; 492*0Sigor@sysoev.ru break; 493*0Sigor@sysoev.ru 494*0Sigor@sysoev.ru default: /* NXT_AGAIN */ 495*0Sigor@sysoev.ru return; 496*0Sigor@sysoev.ru } 497*0Sigor@sysoev.ru 498*0Sigor@sysoev.ru nxt_job_return(nxt_thread(), &jbs->resolve.job, handler); 499*0Sigor@sysoev.ru } 500*0Sigor@sysoev.ru 501*0Sigor@sysoev.ru 502*0Sigor@sysoev.ru static nxt_int_t 503*0Sigor@sysoev.ru nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs) 504*0Sigor@sysoev.ru { 505*0Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 506*0Sigor@sysoev.ru size_t len, socklen; 507*0Sigor@sysoev.ru u_char *path; 508*0Sigor@sysoev.ru nxt_mem_pool_t *mp; 509*0Sigor@sysoev.ru nxt_sockaddr_t *sa; 510*0Sigor@sysoev.ru 511*0Sigor@sysoev.ru /* 512*0Sigor@sysoev.ru * Actual sockaddr_un length can be lesser or even larger than defined 513*0Sigor@sysoev.ru * struct sockaddr_un length (see comment in unix/nxt_socket.h). So 514*0Sigor@sysoev.ru * limit maximum Unix domain socket address length by defined sun_path[] 515*0Sigor@sysoev.ru * length because some OSes accept addresses twice larger than defined 516*0Sigor@sysoev.ru * struct sockaddr_un. Also reserve space for a trailing zero to avoid 517*0Sigor@sysoev.ru * ambiguity, since many OSes accept Unix domain socket addresses 518*0Sigor@sysoev.ru * without a trailing zero. 519*0Sigor@sysoev.ru */ 520*0Sigor@sysoev.ru const size_t max_len = sizeof(struct sockaddr_un) 521*0Sigor@sysoev.ru - offsetof(struct sockaddr_un, sun_path) - 1; 522*0Sigor@sysoev.ru 523*0Sigor@sysoev.ru /* cutting "unix:" */ 524*0Sigor@sysoev.ru len = jbs->addr.len - 5; 525*0Sigor@sysoev.ru path = jbs->addr.data + 5; 526*0Sigor@sysoev.ru 527*0Sigor@sysoev.ru if (len > max_len) { 528*0Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 529*0Sigor@sysoev.ru "unix domain socket \"%V\" name is too long", 530*0Sigor@sysoev.ru &jbs->addr); 531*0Sigor@sysoev.ru return NXT_ERROR; 532*0Sigor@sysoev.ru } 533*0Sigor@sysoev.ru 534*0Sigor@sysoev.ru socklen = offsetof(struct sockaddr_un, sun_path) + len + 1; 535*0Sigor@sysoev.ru 536*0Sigor@sysoev.ru #if (NXT_LINUX) 537*0Sigor@sysoev.ru 538*0Sigor@sysoev.ru /* 539*0Sigor@sysoev.ru * Linux unix(7): 540*0Sigor@sysoev.ru * 541*0Sigor@sysoev.ru * abstract: an abstract socket address is distinguished by the fact 542*0Sigor@sysoev.ru * that sun_path[0] is a null byte ('\0'). The socket's address in 543*0Sigor@sysoev.ru * this namespace is given by the additional bytes in sun_path that 544*0Sigor@sysoev.ru * are covered by the specified length of the address structure. 545*0Sigor@sysoev.ru * (Null bytes in the name have no special significance.) 546*0Sigor@sysoev.ru */ 547*0Sigor@sysoev.ru if (path[0] == '\0') { 548*0Sigor@sysoev.ru socklen--; 549*0Sigor@sysoev.ru } 550*0Sigor@sysoev.ru 551*0Sigor@sysoev.ru #endif 552*0Sigor@sysoev.ru 553*0Sigor@sysoev.ru mp = jbs->resolve.job.mem_pool; 554*0Sigor@sysoev.ru 555*0Sigor@sysoev.ru jbs->resolve.sockaddrs = nxt_mem_alloc(mp, sizeof(void *)); 556*0Sigor@sysoev.ru 557*0Sigor@sysoev.ru if (nxt_fast_path(jbs->resolve.sockaddrs != NULL)) { 558*0Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, socklen); 559*0Sigor@sysoev.ru 560*0Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 561*0Sigor@sysoev.ru jbs->resolve.count = 1; 562*0Sigor@sysoev.ru jbs->resolve.sockaddrs[0] = sa; 563*0Sigor@sysoev.ru 564*0Sigor@sysoev.ru sa->u.sockaddr_un.sun_family = AF_UNIX; 565*0Sigor@sysoev.ru nxt_memcpy(sa->u.sockaddr_un.sun_path, path, len); 566*0Sigor@sysoev.ru 567*0Sigor@sysoev.ru return NXT_OK; 568*0Sigor@sysoev.ru } 569*0Sigor@sysoev.ru } 570*0Sigor@sysoev.ru 571*0Sigor@sysoev.ru return NXT_ERROR; 572*0Sigor@sysoev.ru 573*0Sigor@sysoev.ru #else /* !(NXT_HAVE_UNIX_DOMAIN) */ 574*0Sigor@sysoev.ru 575*0Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 576*0Sigor@sysoev.ru "unix domain socket \"%V\" is not supported", 577*0Sigor@sysoev.ru &jbs->addr); 578*0Sigor@sysoev.ru return NXT_ERROR; 579*0Sigor@sysoev.ru 580*0Sigor@sysoev.ru #endif 581*0Sigor@sysoev.ru } 582*0Sigor@sysoev.ru 583*0Sigor@sysoev.ru 584*0Sigor@sysoev.ru static nxt_int_t 585*0Sigor@sysoev.ru nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs) 586*0Sigor@sysoev.ru { 587*0Sigor@sysoev.ru #if (NXT_INET6) 588*0Sigor@sysoev.ru u_char *p, *addr, *addr_end; 589*0Sigor@sysoev.ru size_t len; 590*0Sigor@sysoev.ru nxt_int_t port; 591*0Sigor@sysoev.ru nxt_mem_pool_t *mp; 592*0Sigor@sysoev.ru nxt_sockaddr_t *sa; 593*0Sigor@sysoev.ru struct in6_addr *in6_addr; 594*0Sigor@sysoev.ru 595*0Sigor@sysoev.ru len = jbs->addr.len - 1; 596*0Sigor@sysoev.ru addr = jbs->addr.data + 1; 597*0Sigor@sysoev.ru 598*0Sigor@sysoev.ru addr_end = nxt_memchr(addr, ']', len); 599*0Sigor@sysoev.ru 600*0Sigor@sysoev.ru if (addr_end == NULL) { 601*0Sigor@sysoev.ru goto invalid_address; 602*0Sigor@sysoev.ru } 603*0Sigor@sysoev.ru 604*0Sigor@sysoev.ru mp = jbs->resolve.job.mem_pool; 605*0Sigor@sysoev.ru 606*0Sigor@sysoev.ru jbs->resolve.sockaddrs = nxt_mem_alloc(mp, sizeof(void *)); 607*0Sigor@sysoev.ru 608*0Sigor@sysoev.ru if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) { 609*0Sigor@sysoev.ru return NXT_ERROR; 610*0Sigor@sysoev.ru } 611*0Sigor@sysoev.ru 612*0Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6)); 613*0Sigor@sysoev.ru 614*0Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 615*0Sigor@sysoev.ru return NXT_ERROR; 616*0Sigor@sysoev.ru } 617*0Sigor@sysoev.ru 618*0Sigor@sysoev.ru jbs->resolve.count = 1; 619*0Sigor@sysoev.ru jbs->resolve.sockaddrs[0] = sa; 620*0Sigor@sysoev.ru 621*0Sigor@sysoev.ru in6_addr = &sa->u.sockaddr_in6.sin6_addr; 622*0Sigor@sysoev.ru 623*0Sigor@sysoev.ru if (nxt_inet6_addr(in6_addr, addr, addr_end - addr) != NXT_OK) { 624*0Sigor@sysoev.ru goto invalid_address; 625*0Sigor@sysoev.ru } 626*0Sigor@sysoev.ru 627*0Sigor@sysoev.ru p = addr_end + 1; 628*0Sigor@sysoev.ru len = (addr + len) - p; 629*0Sigor@sysoev.ru 630*0Sigor@sysoev.ru if (len == 0) { 631*0Sigor@sysoev.ru jbs->no_port = 1; 632*0Sigor@sysoev.ru port = jbs->resolve.port; 633*0Sigor@sysoev.ru goto found; 634*0Sigor@sysoev.ru } 635*0Sigor@sysoev.ru 636*0Sigor@sysoev.ru if (*p == ':') { 637*0Sigor@sysoev.ru port = nxt_int_parse(p + 1, len - 1); 638*0Sigor@sysoev.ru 639*0Sigor@sysoev.ru if (port >= 1 && port <= 65535) { 640*0Sigor@sysoev.ru port = htons((in_port_t) port); 641*0Sigor@sysoev.ru goto found; 642*0Sigor@sysoev.ru } 643*0Sigor@sysoev.ru } 644*0Sigor@sysoev.ru 645*0Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 646*0Sigor@sysoev.ru "invalid port in \"%V\"", &jbs->addr); 647*0Sigor@sysoev.ru 648*0Sigor@sysoev.ru return NXT_ERROR; 649*0Sigor@sysoev.ru 650*0Sigor@sysoev.ru found: 651*0Sigor@sysoev.ru 652*0Sigor@sysoev.ru sa->u.sockaddr_in6.sin6_family = AF_INET6; 653*0Sigor@sysoev.ru sa->u.sockaddr_in6.sin6_port = (in_port_t) port; 654*0Sigor@sysoev.ru 655*0Sigor@sysoev.ru if (IN6_IS_ADDR_UNSPECIFIED(in6_addr)) { 656*0Sigor@sysoev.ru jbs->wildcard = 1; 657*0Sigor@sysoev.ru } 658*0Sigor@sysoev.ru 659*0Sigor@sysoev.ru return NXT_OK; 660*0Sigor@sysoev.ru 661*0Sigor@sysoev.ru invalid_address: 662*0Sigor@sysoev.ru 663*0Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 664*0Sigor@sysoev.ru "invalid IPv6 address in \"%V\"", &jbs->addr); 665*0Sigor@sysoev.ru return NXT_ERROR; 666*0Sigor@sysoev.ru 667*0Sigor@sysoev.ru #else 668*0Sigor@sysoev.ru 669*0Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 670*0Sigor@sysoev.ru "IPv6 socket \"%V\" is not supported", &jbs->addr); 671*0Sigor@sysoev.ru return NXT_ERROR; 672*0Sigor@sysoev.ru 673*0Sigor@sysoev.ru #endif 674*0Sigor@sysoev.ru } 675*0Sigor@sysoev.ru 676*0Sigor@sysoev.ru 677*0Sigor@sysoev.ru static nxt_int_t 678*0Sigor@sysoev.ru nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs) 679*0Sigor@sysoev.ru { 680*0Sigor@sysoev.ru u_char *p, *host; 681*0Sigor@sysoev.ru size_t len; 682*0Sigor@sysoev.ru in_addr_t addr; 683*0Sigor@sysoev.ru nxt_int_t port; 684*0Sigor@sysoev.ru nxt_mem_pool_t *mp; 685*0Sigor@sysoev.ru nxt_sockaddr_t *sa; 686*0Sigor@sysoev.ru 687*0Sigor@sysoev.ru addr = INADDR_ANY; 688*0Sigor@sysoev.ru 689*0Sigor@sysoev.ru len = jbs->addr.len; 690*0Sigor@sysoev.ru host = jbs->addr.data; 691*0Sigor@sysoev.ru 692*0Sigor@sysoev.ru p = nxt_memchr(host, ':', len); 693*0Sigor@sysoev.ru 694*0Sigor@sysoev.ru if (p == NULL) { 695*0Sigor@sysoev.ru 696*0Sigor@sysoev.ru /* single value port, address, or host name */ 697*0Sigor@sysoev.ru 698*0Sigor@sysoev.ru port = nxt_int_parse(host, len); 699*0Sigor@sysoev.ru 700*0Sigor@sysoev.ru if (port > 0) { 701*0Sigor@sysoev.ru if (port < 1 || port > 65535) { 702*0Sigor@sysoev.ru goto invalid_port; 703*0Sigor@sysoev.ru } 704*0Sigor@sysoev.ru 705*0Sigor@sysoev.ru /* "*:XX" */ 706*0Sigor@sysoev.ru port = htons((in_port_t) port); 707*0Sigor@sysoev.ru jbs->resolve.port = (in_port_t) port; 708*0Sigor@sysoev.ru 709*0Sigor@sysoev.ru } else { 710*0Sigor@sysoev.ru jbs->no_port = 1; 711*0Sigor@sysoev.ru 712*0Sigor@sysoev.ru addr = nxt_inet_addr(host, len); 713*0Sigor@sysoev.ru 714*0Sigor@sysoev.ru if (addr == INADDR_NONE) { 715*0Sigor@sysoev.ru jbs->resolve.name.len = len; 716*0Sigor@sysoev.ru jbs->resolve.name.data = host; 717*0Sigor@sysoev.ru 718*0Sigor@sysoev.ru nxt_job_resolve(&jbs->resolve); 719*0Sigor@sysoev.ru return NXT_AGAIN; 720*0Sigor@sysoev.ru } 721*0Sigor@sysoev.ru 722*0Sigor@sysoev.ru /* "x.x.x.x" */ 723*0Sigor@sysoev.ru port = jbs->resolve.port; 724*0Sigor@sysoev.ru } 725*0Sigor@sysoev.ru 726*0Sigor@sysoev.ru } else { 727*0Sigor@sysoev.ru 728*0Sigor@sysoev.ru /* x.x.x.x:XX or host:XX */ 729*0Sigor@sysoev.ru 730*0Sigor@sysoev.ru p++; 731*0Sigor@sysoev.ru len = (host + len) - p; 732*0Sigor@sysoev.ru port = nxt_int_parse(p, len); 733*0Sigor@sysoev.ru 734*0Sigor@sysoev.ru if (port < 1 || port > 65535) { 735*0Sigor@sysoev.ru goto invalid_port; 736*0Sigor@sysoev.ru } 737*0Sigor@sysoev.ru 738*0Sigor@sysoev.ru port = htons((in_port_t) port); 739*0Sigor@sysoev.ru 740*0Sigor@sysoev.ru len = (p - 1) - host; 741*0Sigor@sysoev.ru 742*0Sigor@sysoev.ru if (len != 1 || host[0] != '*') { 743*0Sigor@sysoev.ru addr = nxt_inet_addr(host, len); 744*0Sigor@sysoev.ru 745*0Sigor@sysoev.ru if (addr == INADDR_NONE) { 746*0Sigor@sysoev.ru jbs->resolve.name.len = len; 747*0Sigor@sysoev.ru jbs->resolve.name.data = host; 748*0Sigor@sysoev.ru jbs->resolve.port = (in_port_t) port; 749*0Sigor@sysoev.ru 750*0Sigor@sysoev.ru nxt_job_resolve(&jbs->resolve); 751*0Sigor@sysoev.ru return NXT_AGAIN; 752*0Sigor@sysoev.ru } 753*0Sigor@sysoev.ru 754*0Sigor@sysoev.ru /* "x.x.x.x:XX" */ 755*0Sigor@sysoev.ru } 756*0Sigor@sysoev.ru } 757*0Sigor@sysoev.ru 758*0Sigor@sysoev.ru mp = jbs->resolve.job.mem_pool; 759*0Sigor@sysoev.ru 760*0Sigor@sysoev.ru jbs->resolve.sockaddrs = nxt_mem_alloc(mp, sizeof(void *)); 761*0Sigor@sysoev.ru if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) { 762*0Sigor@sysoev.ru return NXT_ERROR; 763*0Sigor@sysoev.ru } 764*0Sigor@sysoev.ru 765*0Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in)); 766*0Sigor@sysoev.ru 767*0Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) { 768*0Sigor@sysoev.ru jbs->resolve.count = 1; 769*0Sigor@sysoev.ru jbs->resolve.sockaddrs[0] = sa; 770*0Sigor@sysoev.ru 771*0Sigor@sysoev.ru jbs->wildcard = (addr == INADDR_ANY); 772*0Sigor@sysoev.ru 773*0Sigor@sysoev.ru sa->u.sockaddr_in.sin_family = AF_INET; 774*0Sigor@sysoev.ru sa->u.sockaddr_in.sin_port = (in_port_t) port; 775*0Sigor@sysoev.ru sa->u.sockaddr_in.sin_addr.s_addr = addr; 776*0Sigor@sysoev.ru 777*0Sigor@sysoev.ru return NXT_OK; 778*0Sigor@sysoev.ru } 779*0Sigor@sysoev.ru 780*0Sigor@sysoev.ru return NXT_ERROR; 781*0Sigor@sysoev.ru 782*0Sigor@sysoev.ru invalid_port: 783*0Sigor@sysoev.ru 784*0Sigor@sysoev.ru nxt_thread_log_error(jbs->resolve.log_level, 785*0Sigor@sysoev.ru "invalid port in \"%V\"", &jbs->addr); 786*0Sigor@sysoev.ru 787*0Sigor@sysoev.ru return NXT_ERROR; 788*0Sigor@sysoev.ru } 789*0Sigor@sysoev.ru 790*0Sigor@sysoev.ru 791*0Sigor@sysoev.ru in_addr_t 792*0Sigor@sysoev.ru nxt_inet_addr(u_char *buf, size_t len) 793*0Sigor@sysoev.ru { 794*0Sigor@sysoev.ru u_char c, *end; 795*0Sigor@sysoev.ru in_addr_t addr; 796*0Sigor@sysoev.ru nxt_uint_t digit, octet, dots; 797*0Sigor@sysoev.ru 798*0Sigor@sysoev.ru addr = 0; 799*0Sigor@sysoev.ru octet = 0; 800*0Sigor@sysoev.ru dots = 0; 801*0Sigor@sysoev.ru 802*0Sigor@sysoev.ru end = buf + len; 803*0Sigor@sysoev.ru 804*0Sigor@sysoev.ru while (buf < end) { 805*0Sigor@sysoev.ru 806*0Sigor@sysoev.ru c = *buf++; 807*0Sigor@sysoev.ru 808*0Sigor@sysoev.ru digit = c - '0'; 809*0Sigor@sysoev.ru /* values below '0' become large unsigned integers */ 810*0Sigor@sysoev.ru 811*0Sigor@sysoev.ru if (digit < 10) { 812*0Sigor@sysoev.ru octet = octet * 10 + digit; 813*0Sigor@sysoev.ru continue; 814*0Sigor@sysoev.ru } 815*0Sigor@sysoev.ru 816*0Sigor@sysoev.ru if (c == '.' && octet < 256) { 817*0Sigor@sysoev.ru addr = (addr << 8) + octet; 818*0Sigor@sysoev.ru octet = 0; 819*0Sigor@sysoev.ru dots++; 820*0Sigor@sysoev.ru continue; 821*0Sigor@sysoev.ru } 822*0Sigor@sysoev.ru 823*0Sigor@sysoev.ru return INADDR_NONE; 824*0Sigor@sysoev.ru } 825*0Sigor@sysoev.ru 826*0Sigor@sysoev.ru if (dots == 3 && octet < 256) { 827*0Sigor@sysoev.ru addr = (addr << 8) + octet; 828*0Sigor@sysoev.ru return htonl(addr); 829*0Sigor@sysoev.ru } 830*0Sigor@sysoev.ru 831*0Sigor@sysoev.ru return INADDR_NONE; 832*0Sigor@sysoev.ru } 833*0Sigor@sysoev.ru 834*0Sigor@sysoev.ru 835*0Sigor@sysoev.ru #if (NXT_INET6) 836*0Sigor@sysoev.ru 837*0Sigor@sysoev.ru nxt_int_t 838*0Sigor@sysoev.ru nxt_inet6_addr(struct in6_addr *in6_addr, u_char *buf, size_t len) 839*0Sigor@sysoev.ru { 840*0Sigor@sysoev.ru u_char c, *addr, *zero_start, *ipv4, *dst, *src, *end; 841*0Sigor@sysoev.ru nxt_uint_t digit, group, nibbles, groups_left; 842*0Sigor@sysoev.ru 843*0Sigor@sysoev.ru if (len == 0) { 844*0Sigor@sysoev.ru return NXT_ERROR; 845*0Sigor@sysoev.ru } 846*0Sigor@sysoev.ru 847*0Sigor@sysoev.ru end = buf + len; 848*0Sigor@sysoev.ru 849*0Sigor@sysoev.ru if (buf[0] == ':') { 850*0Sigor@sysoev.ru buf++; 851*0Sigor@sysoev.ru } 852*0Sigor@sysoev.ru 853*0Sigor@sysoev.ru addr = in6_addr->s6_addr; 854*0Sigor@sysoev.ru zero_start = NULL; 855*0Sigor@sysoev.ru groups_left = 8; 856*0Sigor@sysoev.ru nibbles = 0; 857*0Sigor@sysoev.ru group = 0; 858*0Sigor@sysoev.ru ipv4 = NULL; 859*0Sigor@sysoev.ru 860*0Sigor@sysoev.ru while (buf < end) { 861*0Sigor@sysoev.ru c = *buf++; 862*0Sigor@sysoev.ru 863*0Sigor@sysoev.ru if (c == ':') { 864*0Sigor@sysoev.ru if (nibbles != 0) { 865*0Sigor@sysoev.ru ipv4 = buf; 866*0Sigor@sysoev.ru 867*0Sigor@sysoev.ru *addr++ = (u_char) (group >> 8); 868*0Sigor@sysoev.ru *addr++ = (u_char) (group & 0xff); 869*0Sigor@sysoev.ru groups_left--; 870*0Sigor@sysoev.ru 871*0Sigor@sysoev.ru if (groups_left != 0) { 872*0Sigor@sysoev.ru nibbles = 0; 873*0Sigor@sysoev.ru group = 0; 874*0Sigor@sysoev.ru continue; 875*0Sigor@sysoev.ru } 876*0Sigor@sysoev.ru 877*0Sigor@sysoev.ru } else { 878*0Sigor@sysoev.ru if (zero_start == NULL) { 879*0Sigor@sysoev.ru ipv4 = buf; 880*0Sigor@sysoev.ru zero_start = addr; 881*0Sigor@sysoev.ru continue; 882*0Sigor@sysoev.ru } 883*0Sigor@sysoev.ru } 884*0Sigor@sysoev.ru 885*0Sigor@sysoev.ru return NXT_ERROR; 886*0Sigor@sysoev.ru } 887*0Sigor@sysoev.ru 888*0Sigor@sysoev.ru if (c == '.' && nibbles != 0) { 889*0Sigor@sysoev.ru 890*0Sigor@sysoev.ru if (groups_left < 2 || ipv4 == NULL) { 891*0Sigor@sysoev.ru return NXT_ERROR; 892*0Sigor@sysoev.ru } 893*0Sigor@sysoev.ru 894*0Sigor@sysoev.ru group = nxt_inet_addr(ipv4, end - ipv4); 895*0Sigor@sysoev.ru if (group == INADDR_NONE) { 896*0Sigor@sysoev.ru return NXT_ERROR; 897*0Sigor@sysoev.ru } 898*0Sigor@sysoev.ru 899*0Sigor@sysoev.ru group = ntohl(group); 900*0Sigor@sysoev.ru 901*0Sigor@sysoev.ru *addr++ = (u_char) ((group >> 24) & 0xff); 902*0Sigor@sysoev.ru *addr++ = (u_char) ((group >> 16) & 0xff); 903*0Sigor@sysoev.ru groups_left--; 904*0Sigor@sysoev.ru 905*0Sigor@sysoev.ru /* the low 16-bit are copied below */ 906*0Sigor@sysoev.ru break; 907*0Sigor@sysoev.ru } 908*0Sigor@sysoev.ru 909*0Sigor@sysoev.ru nibbles++; 910*0Sigor@sysoev.ru 911*0Sigor@sysoev.ru if (nibbles > 4) { 912*0Sigor@sysoev.ru return NXT_ERROR; 913*0Sigor@sysoev.ru } 914*0Sigor@sysoev.ru 915*0Sigor@sysoev.ru group <<= 4; 916*0Sigor@sysoev.ru 917*0Sigor@sysoev.ru digit = c - '0'; 918*0Sigor@sysoev.ru /* values below '0' become large unsigned integers */ 919*0Sigor@sysoev.ru 920*0Sigor@sysoev.ru if (digit < 10) { 921*0Sigor@sysoev.ru group += digit; 922*0Sigor@sysoev.ru continue; 923*0Sigor@sysoev.ru } 924*0Sigor@sysoev.ru 925*0Sigor@sysoev.ru c |= 0x20; 926*0Sigor@sysoev.ru digit = c - 'a'; 927*0Sigor@sysoev.ru /* values below 'a' become large unsigned integers */ 928*0Sigor@sysoev.ru 929*0Sigor@sysoev.ru if (digit < 6) { 930*0Sigor@sysoev.ru group += 10 + digit; 931*0Sigor@sysoev.ru continue; 932*0Sigor@sysoev.ru } 933*0Sigor@sysoev.ru 934*0Sigor@sysoev.ru return NXT_ERROR; 935*0Sigor@sysoev.ru } 936*0Sigor@sysoev.ru 937*0Sigor@sysoev.ru if (nibbles == 0 && zero_start == NULL) { 938*0Sigor@sysoev.ru return NXT_ERROR; 939*0Sigor@sysoev.ru } 940*0Sigor@sysoev.ru 941*0Sigor@sysoev.ru *addr++ = (u_char) (group >> 8); 942*0Sigor@sysoev.ru *addr++ = (u_char) (group & 0xff); 943*0Sigor@sysoev.ru groups_left--; 944*0Sigor@sysoev.ru 945*0Sigor@sysoev.ru if (groups_left != 0) { 946*0Sigor@sysoev.ru 947*0Sigor@sysoev.ru if (zero_start != NULL) { 948*0Sigor@sysoev.ru 949*0Sigor@sysoev.ru /* moving part before consecutive zero groups to the end */ 950*0Sigor@sysoev.ru 951*0Sigor@sysoev.ru groups_left *= 2; 952*0Sigor@sysoev.ru src = addr - 1; 953*0Sigor@sysoev.ru dst = src + groups_left; 954*0Sigor@sysoev.ru 955*0Sigor@sysoev.ru while (src >= zero_start) { 956*0Sigor@sysoev.ru *dst-- = *src--; 957*0Sigor@sysoev.ru } 958*0Sigor@sysoev.ru 959*0Sigor@sysoev.ru nxt_memzero(zero_start, groups_left); 960*0Sigor@sysoev.ru 961*0Sigor@sysoev.ru return NXT_OK; 962*0Sigor@sysoev.ru } 963*0Sigor@sysoev.ru 964*0Sigor@sysoev.ru } else { 965*0Sigor@sysoev.ru if (zero_start == NULL) { 966*0Sigor@sysoev.ru return NXT_OK; 967*0Sigor@sysoev.ru } 968*0Sigor@sysoev.ru } 969*0Sigor@sysoev.ru 970*0Sigor@sysoev.ru return NXT_ERROR; 971*0Sigor@sysoev.ru } 972*0Sigor@sysoev.ru 973*0Sigor@sysoev.ru #endif 974