X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=blobdiff_plain;f=libatalk%2Futil%2Fsocket.c;h=8b4e6e7f434098e5c3b6841ea3598abd782730ff;hp=5843d1d632a1b923af5efd4bae0a295fa4400ea7;hb=75fe310224dffb96868d7f2cb1ec9125a84f2a08;hpb=21b17908047ad4f3b00a9f6a4655494d874390b0 diff --git a/libatalk/util/socket.c b/libatalk/util/socket.c index 5843d1d6..8b4e6e7f 100644 --- a/libatalk/util/socket.c +++ b/libatalk/util/socket.c @@ -1,5 +1,5 @@ /* - $Id: socket.c,v 1.1 2009-10-26 12:35:56 franklahm Exp $ + $Id: socket.c,v 1.2 2009-11-05 14:38:08 franklahm Exp $ Copyright (c) 2009 Frank Lahm This program is free software; you can redistribute it and/or modify @@ -19,6 +19,14 @@ #include #include +#include +#include +#include +#include + +#include + +static char ipv4mapprefix[] = {0,0,0,0,0,0,0,0,0,0,0xff,0xff}; int setnonblock(int fd, int cmd) { @@ -39,3 +47,105 @@ int setnonblock(int fd, int cmd) return 0; } + +const char *getip_string(const struct sockaddr *sa) +{ + static char ip4[INET_ADDRSTRLEN]; + static char ip6[INET6_ADDRSTRLEN]; + + switch (sa->sa_family) { + + case AF_INET: { + const struct sockaddr_in *sai4 = (const struct sockaddr_in *)sa; + if ((inet_ntop(AF_INET, &(sai4->sin_addr), ip4, INET_ADDRSTRLEN)) == NULL) + return "0.0.0.0"; + return ip4; + } + case AF_INET6: { + const struct sockaddr_in6 *sai6 = (const struct sockaddr_in6 *)sa; + if ((inet_ntop(AF_INET6, &(sai6->sin6_addr), ip6, INET6_ADDRSTRLEN)) == NULL) + return "::0"; + + /* Deal with IPv6 mapped IPv4 addresses*/ + if ((memcmp(sai6->sin6_addr.s6_addr, ipv4mapprefix, sizeof(ipv4mapprefix))) == 0) + return (strrchr(ip6, ':') + 1); + return ip6; + } + default: + return "getip_string ERROR"; + } + + /* We never get here */ +} + +unsigned int getip_port(const struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET) { /* IPv4 */ + const struct sockaddr_in *sai4 = (const struct sockaddr_in *)sa; + return ntohs(sai4->sin_port); + } else { /* IPv6 */ + const struct sockaddr_in6 *sai6 = (const struct sockaddr_in6 *)sa; + return ntohs(sai6->sin6_port); + } + + /* We never get here */ +} + +void apply_ip_mask(struct sockaddr *sa, uint32_t mask) +{ + if (mask < 0) + return; + + switch (sa->sa_family) { + case AF_INET: { + if (mask >= 32) + return; + + struct sockaddr_in *si = (struct sockaddr_in *)sa; + uint32_t nmask = mask ? ~((1 << (32 - mask)) - 1) : 0; + si->sin_addr.s_addr &= htonl(nmask); + break; + } + case AF_INET6: { + if (mask >= 128) + return; + + int i, maskbytes, maskbits; + struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)sa; + + /* Deal with IPv6 mapped IPv4 addresses*/ + if ((memcmp(si6->sin6_addr.s6_addr, ipv4mapprefix, sizeof(ipv4mapprefix))) == 0) { + mask += 96; + if (mask >= 128) + return; + } + + maskbytes = (128 - mask) / 8; /* maskbytes really are those that will be 0'ed */ + maskbits = mask % 8; + + for (i = maskbytes - 1; i >= 0; i--) + si6->sin6_addr.s6_addr[15 - i] = 0; + if (maskbits) + si6->sin6_addr.s6_addr[15 - maskbytes] &= ~((1 << (8 - maskbits)) - 1); + break; + } + default: + break; + } +} + +int compare_ip(const struct sockaddr *sa1, const struct sockaddr *sa2) +{ + int ret; + const char *ip1; + const char *ip2; + + ip1 = strdup(getip_string(sa1)); + ip2 = getip_string(sa2); + + ret = strcmp(ip1, ip2); + + free(ip1); + + return ret; +}