chiark / gitweb /
ff533c939ca0fd6baf76c2e29d77a7230d8fa50f
[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 static int inet_rev_parsecomp(const char *p, size_t n)
68 {
69   int i = 0;
70   if (n > 3) return -1;
71
72   while (n--) {
73     if ('0' <= *p && *p <= '9') i = 10*i + *p++ - '0';
74     else return -1;
75   }
76   return i;
77 }
78
79 static void inet_rev_mkaddr(union gen_addr *addr, const byte *ipv)
80 {
81   addr->v4.s_addr = htonl((ipv[3]<<24) | (ipv[2]<<16) |
82                           (ipv[1]<<8) | (ipv[0]));
83 }
84
85 static char *inet_rev_mkname(struct sockaddr *sa, char *buf)
86 {
87   unsigned long a = ntohl(SIN(sa)->sin_addr.s_addr);
88   int i;
89
90   for (i = 0; i < 4; i++) {
91     if (i) *buf++ = '.';
92     buf += sprintf(buf, "%d", (int)(a & 0xff));
93     a >>= 8;
94   }
95   return buf;
96 }
97
98 const afinfo adns__inet_afinfo = {
99   AF_INET, 32, '.', 4, 3, adns_r_a,
100   inet_sockaddr_to_inaddr, inet_prefix_mask, inet_guess_len, inet_matchp,
101   inet_rev_parsecomp, inet_rev_mkaddr, inet_rev_mkname
102 };
103
104 /*
105  * IPv6
106  */
107
108 #define SIN6(sa) ((struct sockaddr_in6 *)(sa))
109
110 static void *inet6_sockaddr_to_inaddr(struct sockaddr *sa)
111   { return &SIN6(sa)->sin6_addr; }
112
113 static void inet6_prefix_mask(int len, union gen_addr *mask)
114 {
115   int i = len/8, j = len%8;
116   unsigned char *m = mask->v6.s6_addr;
117
118   assert(len < 128);
119   memset(m, 0xff, i);
120   if (j) m[i++] = (0xff << (8-j)) & 0xff;
121   memset(m + i, 0, 16-i);
122 }
123
124 static int inet6_guess_len(const union gen_addr *addr)
125   { return 64; }
126
127 static int inet6_matchp(const union gen_addr *addr,
128                         const union gen_addr *base,
129                         const union gen_addr *mask)
130 {
131   int i;
132   const char *a = addr->v6.s6_addr;
133   const char *b = base->v6.s6_addr;
134   const char *m = mask->v6.s6_addr;
135
136   for (i = 0; i < 16; i++)
137     if ((a[i] & m[i]) != b[i]) return 0;
138   return 1;
139 }
140
141 static int inet6_rev_parsecomp(const char *p, size_t n)
142 {
143   if (n != 1) return -1;
144   else if ('0' <= *p && *p <= '9') return *p - '0';
145   else if ('a' <= *p && *p <= 'f') return *p - 'a' + 10;
146   else if ('A' <= *p && *p <= 'F') return *p - 'a' + 10;
147   else return -1;
148 }
149
150 static void inet6_rev_mkaddr(union gen_addr *addr, const byte *ipv)
151 {
152   unsigned char *a = addr->v6.s6_addr;
153   int i;
154
155   for (i = 0; i < 16; i++)
156     a[i] = (ipv[31-2*i] << 4) | (ipv[30-2*i] << 0);
157 }
158
159 static char *inet6_rev_mkname(struct sockaddr *sa, char *buf)
160 {
161   unsigned char *a = SIN6(sa)->sin6_addr.s6_addr + 16;
162   unsigned c, y;
163   int i, j;
164
165   for (i = 0; i < 16; i++) {
166     c = *--a;
167     for (j = 0; j < 2; j++) {
168       if (i || j) *buf++ = '.';
169       y = c & 0xf;
170       if (y < 10) *buf++ = y + '0';
171       else *buf++ = y - 10 + 'a';
172       c >>= 4;
173     }
174   }
175   return buf;
176 }
177
178 const afinfo adns__inet6_afinfo = {
179   AF_INET6, 128, ':', 32, 1, adns_r_aaaa,
180   inet6_sockaddr_to_inaddr, inet6_prefix_mask, inet6_guess_len, inet6_matchp,
181   inet6_rev_parsecomp, inet6_rev_mkaddr, inet6_rev_mkname
182 };