chiark / gitweb /
40b8f2b6134bbd277a2158d4dd182ca2d1783965
[adns] / src / addrfam.c
1 /*
2  * addrfam.c
3  * - address-family specific code
4  */
5 /*
6  *  This file is part of adns, which is
7  *    Copyright (C) 1997-2000,2003,2006  Ian Jackson
8  *    Copyright (C) 1999-2000,2003,2006  Tony Finch
9  *    Copyright (C) 1991 Massachusetts Institute of Technology
10  *  (See the file INSTALL for full details.)
11  *  
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2, or (at your option)
15  *  any later version.
16  *  
17  *  This program is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU General Public License for more details.
21  *  
22  *  You should have received a copy of the GNU General Public License
23  *  along with this program; if not, write to the Free Software Foundation,
24  *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
25  */
26
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <limits.h>
30 #include <unistd.h>
31
32 #include <sys/types.h>
33 #include <netdb.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37
38 #include "internal.h"
39
40 /*
41  * IPv4
42  */
43
44 #define SIN(sa) ((struct sockaddr_in *)(sa))
45
46 static void *inet_sockaddr_to_inaddr(struct sockaddr *sa)
47   { return &SIN(sa)->sin_addr; }
48
49 static void inet_prefix_mask(int len, union gen_addr *mask)
50   { mask->v4.s_addr = htonl(!len ? 0 : 0xffffffff << (32 - len)); }
51
52 static int inet_guess_len(const union gen_addr *addr)
53 {
54   unsigned a = (ntohl(addr->v4.s_addr) >> 24) & 0xff;
55
56   if (a < 128) return 8;
57   else if (a < 192) return 16;
58   else if (a < 224) return 24;
59   else return -1;
60 }
61
62 static int inet_matchp(const union gen_addr *addr,
63                        const union gen_addr *base,
64                        const union gen_addr *mask)
65   { return (addr->v4.s_addr & mask->v4.s_addr) == base->v4.s_addr; }
66
67 const afinfo adns__inet_afinfo = {
68   AF_INET, 32, '.',
69   inet_sockaddr_to_inaddr, inet_prefix_mask, inet_guess_len, inet_matchp
70 };
71
72 /*
73  * IPv6
74  */
75
76 #define SIN6(sa) ((struct sockaddr_in6 *)(sa))
77
78 static void *inet6_sockaddr_to_inaddr(struct sockaddr *sa)
79   { return &SIN6(sa)->sin6_addr; }
80
81 static void inet6_prefix_mask(int len, union gen_addr *mask)
82 {
83   int i = len/8, j = len%8;
84   unsigned char *m = mask->v6.s6_addr;
85
86   assert(len < 128);
87   memset(m, 0xff, i);
88   if (j) m[i++] = (0xff << (8-j)) & 0xff;
89   memset(m + i, 0, 16-i);
90 }
91
92 static int inet6_guess_len(const union gen_addr *addr)
93   { return 64; }
94
95 static int inet6_matchp(const union gen_addr *addr,
96                         const union gen_addr *base,
97                         const union gen_addr *mask)
98 {
99   int i;
100   const char *a = addr->v6.s6_addr;
101   const char *b = base->v6.s6_addr;
102   const char *m = mask->v6.s6_addr;
103
104   for (i = 0; i < 16; i++)
105     if ((a[i] & m[i]) != b[i]) return 0;
106   return 1;
107 }
108
109 const afinfo adns__inet6_afinfo = {
110   AF_INET6, 128, ':',
111   inet6_sockaddr_to_inaddr, inet6_prefix_mask, inet6_guess_len, inet6_matchp
112 };