Support IPv6 PTR lookups.
[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 };