[BACK]Return to addrmatch.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/addrmatch.c between version 1.15 and 1.16

version 1.15, 2020/10/18 11:32:01 version 1.16, 2021/01/09 11:58:50
Line 27 
Line 27 
 #include <stdio.h>  #include <stdio.h>
 #include <stdarg.h>  #include <stdarg.h>
   
   #include "addr.h"
 #include "match.h"  #include "match.h"
 #include "log.h"  #include "log.h"
   
 struct xaddr {  
         sa_family_t     af;  
         union {  
                 struct in_addr          v4;  
                 struct in6_addr         v6;  
                 u_int8_t                addr8[16];  
                 u_int32_t               addr32[4];  
         } xa;               /* 128-bit address */  
         u_int32_t       scope_id;       /* iface scope id for v6 */  
 #define v4      xa.v4  
 #define v6      xa.v6  
 #define addr8   xa.addr8  
 #define addr32  xa.addr32  
 };  
   
 static int  
 addr_unicast_masklen(int af)  
 {  
         switch (af) {  
         case AF_INET:  
                 return 32;  
         case AF_INET6:  
                 return 128;  
         default:  
                 return -1;  
         }  
 }  
   
 static inline int  
 masklen_valid(int af, u_int masklen)  
 {  
         switch (af) {  
         case AF_INET:  
                 return masklen <= 32 ? 0 : -1;  
         case AF_INET6:  
                 return masklen <= 128 ? 0 : -1;  
         default:  
                 return -1;  
         }  
 }  
   
 /*  
  * Convert struct sockaddr to struct xaddr  
  * Returns 0 on success, -1 on failure.  
  */  
 static int  
 addr_sa_to_xaddr(struct sockaddr *sa, socklen_t slen, struct xaddr *xa)  
 {  
         struct sockaddr_in *in4 = (struct sockaddr_in *)sa;  
         struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;  
   
         memset(xa, '\0', sizeof(*xa));  
   
         switch (sa->sa_family) {  
         case AF_INET:  
                 if (slen < (socklen_t)sizeof(*in4))  
                         return -1;  
                 xa->af = AF_INET;  
                 memcpy(&xa->v4, &in4->sin_addr, sizeof(xa->v4));  
                 break;  
         case AF_INET6:  
                 if (slen < (socklen_t)sizeof(*in6))  
                         return -1;  
                 xa->af = AF_INET6;  
                 memcpy(&xa->v6, &in6->sin6_addr, sizeof(xa->v6));  
                 xa->scope_id = in6->sin6_scope_id;  
                 break;  
         default:  
                 return -1;  
         }  
   
         return 0;  
 }  
   
 /*  
  * Calculate a netmask of length 'l' for address family 'af' and  
  * store it in 'n'.  
  * Returns 0 on success, -1 on failure.  
  */  
 static int  
 addr_netmask(int af, u_int l, struct xaddr *n)  
 {  
         int i;  
   
         if (masklen_valid(af, l) != 0 || n == NULL)  
                 return -1;  
   
         memset(n, '\0', sizeof(*n));  
         switch (af) {  
         case AF_INET:  
                 n->af = AF_INET;  
                 if (l == 0)  
                         return 0;  
                 n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff);  
                 return 0;  
         case AF_INET6:  
                 n->af = AF_INET6;  
                 for (i = 0; i < 4 && l >= 32; i++, l -= 32)  
                         n->addr32[i] = 0xffffffffU;  
                 if (i < 4 && l != 0)  
                         n->addr32[i] = htonl((0xffffffff << (32 - l)) &  
                             0xffffffff);  
                 return 0;  
         default:  
                 return -1;  
         }  
 }  
   
 /*  
  * Perform logical AND of addresses 'a' and 'b', storing result in 'dst'.  
  * Returns 0 on success, -1 on failure.  
  */  
 static int  
 addr_and(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b)  
 {  
         int i;  
   
         if (dst == NULL || a == NULL || b == NULL || a->af != b->af)  
                 return -1;  
   
         memcpy(dst, a, sizeof(*dst));  
         switch (a->af) {  
         case AF_INET:  
                 dst->v4.s_addr &= b->v4.s_addr;  
                 return 0;  
         case AF_INET6:  
                 dst->scope_id = a->scope_id;  
                 for (i = 0; i < 4; i++)  
                         dst->addr32[i] &= b->addr32[i];  
                 return 0;  
         default:  
                 return -1;  
         }  
 }  
   
 /*  
  * Compare addresses 'a' and 'b'  
  * Return 0 if addresses are identical, -1 if (a < b) or 1 if (a > b)  
  */  
 static int  
 addr_cmp(const struct xaddr *a, const struct xaddr *b)  
 {  
         int i;  
   
         if (a->af != b->af)  
                 return a->af == AF_INET6 ? 1 : -1;  
   
         switch (a->af) {  
         case AF_INET:  
                 if (a->v4.s_addr == b->v4.s_addr)  
                         return 0;  
                 return ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr) ? 1 : -1;  
         case AF_INET6:  
                 for (i = 0; i < 16; i++)  
                         if (a->addr8[i] - b->addr8[i] != 0)  
                                 return a->addr8[i] > b->addr8[i] ? 1 : -1;  
                 if (a->scope_id == b->scope_id)  
                         return 0;  
                 return a->scope_id > b->scope_id ? 1 : -1;  
         default:  
                 return -1;  
         }  
 }  
   
 /*  
  * Parse string address 'p' into 'n'  
  * Returns 0 on success, -1 on failure.  
  */  
 static int  
 addr_pton(const char *p, struct xaddr *n)  
 {  
         struct addrinfo hints, *ai = NULL;  
         int ret = -1;  
   
         memset(&hints, '\0', sizeof(hints));  
         hints.ai_flags = AI_NUMERICHOST;  
   
         if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0)  
                 goto out;  
         if (ai == NULL || ai->ai_addr == NULL)  
                 goto out;  
         if (n != NULL && addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen, n) == -1)  
                 goto out;  
         /* success */  
         ret = 0;  
  out:  
         if (ai != NULL)  
                 freeaddrinfo(ai);  
         return ret;  
 }  
   
 /*  
  * Perform bitwise negation of address  
  * Returns 0 on success, -1 on failure.  
  */  
 static int  
 addr_invert(struct xaddr *n)  
 {  
         int i;  
   
         if (n == NULL)  
                 return (-1);  
   
         switch (n->af) {  
         case AF_INET:  
                 n->v4.s_addr = ~n->v4.s_addr;  
                 return (0);  
         case AF_INET6:  
                 for (i = 0; i < 4; i++)  
                         n->addr32[i] = ~n->addr32[i];  
                 return (0);  
         default:  
                 return (-1);  
         }  
 }  
   
 /*  
  * Calculate a netmask of length 'l' for address family 'af' and  
  * store it in 'n'.  
  * Returns 0 on success, -1 on failure.  
  */  
 static int  
 addr_hostmask(int af, u_int l, struct xaddr *n)  
 {  
         if (addr_netmask(af, l, n) == -1 || addr_invert(n) == -1)  
                 return (-1);  
         return (0);  
 }  
   
 /*  
  * Test whether address 'a' is all zeros (i.e. 0.0.0.0 or ::)  
  * Returns 0 on if address is all-zeros, -1 if not all zeros or on failure.  
  */  
 static int  
 addr_is_all0s(const struct xaddr *a)  
 {  
         int i;  
   
         switch (a->af) {  
         case AF_INET:  
                 return (a->v4.s_addr == 0 ? 0 : -1);  
         case AF_INET6:;  
                 for (i = 0; i < 4; i++)  
                         if (a->addr32[i] != 0)  
                                 return (-1);  
                 return (0);  
         default:  
                 return (-1);  
         }  
 }  
   
 /*  
  * Test whether host portion of address 'a', as determined by 'masklen'  
  * is all zeros.  
  * Returns 0 on if host portion of address is all-zeros,  
  * -1 if not all zeros or on failure.  
  */  
 static int  
 addr_host_is_all0s(const struct xaddr *a, u_int masklen)  
 {  
         struct xaddr tmp_addr, tmp_mask, tmp_result;  
   
         memcpy(&tmp_addr, a, sizeof(tmp_addr));  
         if (addr_hostmask(a->af, masklen, &tmp_mask) == -1)  
                 return (-1);  
         if (addr_and(&tmp_result, &tmp_addr, &tmp_mask) == -1)  
                 return (-1);  
         return (addr_is_all0s(&tmp_result));  
 }  
   
 /*  
  * Parse a CIDR address (x.x.x.x/y or xxxx:yyyy::/z).  
  * Return -1 on parse error, -2 on inconsistency or 0 on success.  
  */  
 static int  
 addr_pton_cidr(const char *p, struct xaddr *n, u_int *l)  
 {  
         struct xaddr tmp;  
         long unsigned int masklen = 999;  
         char addrbuf[64], *mp, *cp;  
   
         /* Don't modify argument */  
         if (p == NULL || strlcpy(addrbuf, p, sizeof(addrbuf)) >= sizeof(addrbuf))  
                 return -1;  
   
         if ((mp = strchr(addrbuf, '/')) != NULL) {  
                 *mp = '\0';  
                 mp++;  
                 masklen = strtoul(mp, &cp, 10);  
                 if (*mp == '\0' || *cp != '\0' || masklen > 128)  
                         return -1;  
         }  
   
         if (addr_pton(addrbuf, &tmp) == -1)  
                 return -1;  
   
         if (mp == NULL)  
                 masklen = addr_unicast_masklen(tmp.af);  
         if (masklen_valid(tmp.af, masklen) == -1)  
                 return -2;  
         if (addr_host_is_all0s(&tmp, masklen) != 0)  
                 return -2;  
   
         if (n != NULL)  
                 memcpy(n, &tmp, sizeof(*n));  
         if (l != NULL)  
                 *l = masklen;  
   
         return 0;  
 }  
   
 static int  
 addr_netmatch(const struct xaddr *host, const struct xaddr *net, u_int masklen)  
 {  
         struct xaddr tmp_mask, tmp_result;  
   
         if (host->af != net->af)  
                 return -1;  
   
         if (addr_netmask(host->af, masklen, &tmp_mask) == -1)  
                 return -1;  
         if (addr_and(&tmp_result, host, &tmp_mask) == -1)  
                 return -1;  
         return addr_cmp(&tmp_result, net);  
 }  
   
 /*  /*
  * Match "addr" against list pattern list "_list", which may contain a   * Match "addr" against list pattern list "_list", which may contain a

Legend:
Removed from v.1.15  
changed lines
  Added in v.1.16