static int ip2addr(const char *ip, unsigned short port, ACL_SOCKADDR *saddr) { memset(saddr, 0, sizeof(ACL_SOCKADDR)); if (acl_valid_ipv4_hostaddr(ip, 0)) { saddr->sa.sa_family = AF_INET; saddr->in.sin_port = htons(port); if (inet_pton(AF_INET, ip, &saddr->in.sin_addr) == 1) { return 1; } acl_msg_error("%s(%d): invalid ip=%s", __FUNCTION__, __LINE__, ip); } #ifdef AF_INET6 else if (acl_valid_ipv6_hostaddr(ip, 0)) { saddr->sa.sa_family = AF_INET6; saddr->in6.sin6_port = htons(port); if (inet_pton(AF_INET6, ip, &saddr->in6.sin6_addr) == 1) { return 1; } acl_msg_error("%s(%d): invalid ip=%s", __FUNCTION__, __LINE__, ip); } #endif return 0; }
size_t acl_sane_pton(const char *src, struct sockaddr *dst) { int af; if (acl_valid_ipv4_hostaddr(src, 0)) { af = AF_INET; } else if (acl_valid_ipv6_hostaddr(src, 0)) { af = AF_INET6; } else if (acl_valid_unix(src)) { af = AF_UNIX; } else { return 0; } return acl_inet_pton(af, src, dst); }
int acl_valid_hostaddr(const char *addr, int gripe) { const char *myname = "acl_valid_hostaddr"; /* * Trivial cases first. */ if (*addr == 0) { if (gripe) acl_msg_warn("%s: empty address", myname); return (0); } /* * Protocol-dependent processing next. */ if (strchr(addr, ':') != 0) return (acl_valid_ipv6_hostaddr(addr, gripe)); else return (acl_valid_ipv4_hostaddr(addr, gripe)); }
int acl_valid_ipv6_hostaddr(const char *addr, int gripe) { const char *myname = "acl_valid_ipv6_hostaddr"; int null_field = 0; int field = 0; const unsigned char *cp = (const unsigned char *) addr; int len = 0; /* * FIX 200501 The IPv6 patch validated syntax with getaddrinfo(), but I * am not confident that everyone's system library routines are robust * enough, like buffer overflow free. Remember, the valid_hostmumble() * routines are meant to protect Postfix against malformed information * in data received from the network. * * We require eight-field hex addresses of the form 0:1:2:3:4:5:6:7, * 0:1:2:3:4:5:6a.6b.7c.7d, or some :: compressed version of the same. * * Note: the character position is advanced inside the loop. I have added * comments to show why we can't get stuck. */ for (;;) { switch (*cp) { case 0: /* Terminate the loop. */ if (field < 2) { if (gripe) acl_msg_warn("%s: too few `:' in IPv6" " address: %.100s", myname, addr); return (0); } else if (len == 0 && null_field != field - 1) { if (gripe) acl_msg_warn("%s: bad null last field" " in IPv6 address: %.100s", myname, addr); return (0); } else return (1); case '.': /* Terminate the loop. */ if (field < 2 || field > 6) { if (gripe) acl_msg_warn("%s: malformed IPv4-in-IPv6" " address: %.100s", myname, addr); return (0); } /* NOT: acl_valid_hostaddr(). Avoid recursion. */ return (acl_valid_ipv4_hostaddr((const char *) cp - len, gripe)); case ':': /* advance by exactly 1 character position or terminate. */ if (field == 0 && len == 0 && ACL_ISALNUM(cp[1])) { if (gripe) acl_msg_warn("%s: bad null first field" " in IPv6 address: %.100s", myname, addr); return (0); } field++; if (field > 7) { if (gripe) acl_msg_warn("%s: too many `:' in" " IPv6 address: %.100s", myname, addr); return (0); } cp++; len = 0; if (*cp == ':') { if (null_field > 0) { if (gripe) acl_msg_warn("%s: too many `::'" " in IPv6 address: %.100s", myname, addr); return (0); } null_field = field; } break; default: /* Advance by at least 1 character position or terminate. */ len = (int) strspn((const char *) cp, "0123456789abcdefABCDEF"); if (len /* - strspn((char *) cp, "0") */ > 4) { if (gripe) acl_msg_warn("%s: malformed IPv6 address: %.100s", myname, addr); return (0); } if (len <= 0) { if (gripe) acl_msg_warn("%s: invalid character" " %d(decimal) in IPv6 address: %.100s", myname, *cp, addr); return (0); } cp += len; break; } } }
int acl_is_ipv4(const char *ip) { return acl_valid_ipv4_hostaddr(ip, 0); }