Support IPv6 PTR lookups.
[adns] / src / addrfam.c
CommitLineData
9136cf0c
MW
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
46static void *inet_sockaddr_to_inaddr(struct sockaddr *sa)
47 { return &SIN(sa)->sin_addr; }
48
49static void inet_prefix_mask(int len, union gen_addr *mask)
50 { mask->v4.s_addr = htonl(!len ? 0 : 0xffffffff << (32 - len)); }
51
52static 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
62static 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
8a53cf7f
MW
67static 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
79static 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
85static 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
9136cf0c 98const afinfo adns__inet_afinfo = {
8a53cf7f
MW
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
9136cf0c
MW
102};
103
104/*
105 * IPv6
106 */
107
108#define SIN6(sa) ((struct sockaddr_in6 *)(sa))
109
110static void *inet6_sockaddr_to_inaddr(struct sockaddr *sa)
111 { return &SIN6(sa)->sin6_addr; }
112
113static 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
124static int inet6_guess_len(const union gen_addr *addr)
125 { return 64; }
126
127static 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
8a53cf7f
MW
141static 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
150static 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
159static 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
9136cf0c 178const afinfo adns__inet6_afinfo = {
8a53cf7f
MW
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
9136cf0c 182};