chiark / gitweb /
Support transport over IPv6.
[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))
705b9b15 45#define CSIN(sa) ((const struct sockaddr_in *)(sa))
9136cf0c
MW
46
47static void *inet_sockaddr_to_inaddr(struct sockaddr *sa)
48 { return &SIN(sa)->sin_addr; }
49
705b9b15
MW
50static int inet_sockaddr_equalp(const struct sockaddr *sa,
51 const struct sockaddr *sb)
52{
53 const struct sockaddr_in *sina = CSIN(sa), *sinb = CSIN(sb);
54 return (sina->sin_addr.s_addr == sinb->sin_addr.s_addr &&
55 sina->sin_port == sinb->sin_port);
56}
57
9136cf0c
MW
58static void inet_prefix_mask(int len, union gen_addr *mask)
59 { mask->v4.s_addr = htonl(!len ? 0 : 0xffffffff << (32 - len)); }
60
61static int inet_guess_len(const union gen_addr *addr)
62{
63 unsigned a = (ntohl(addr->v4.s_addr) >> 24) & 0xff;
64
65 if (a < 128) return 8;
66 else if (a < 192) return 16;
67 else if (a < 224) return 24;
68 else return -1;
69}
70
71static int inet_matchp(const union gen_addr *addr,
72 const union gen_addr *base,
73 const union gen_addr *mask)
74 { return (addr->v4.s_addr & mask->v4.s_addr) == base->v4.s_addr; }
75
8a53cf7f
MW
76static int inet_rev_parsecomp(const char *p, size_t n)
77{
78 int i = 0;
79 if (n > 3) return -1;
80
81 while (n--) {
82 if ('0' <= *p && *p <= '9') i = 10*i + *p++ - '0';
83 else return -1;
84 }
85 return i;
86}
87
88static void inet_rev_mkaddr(union gen_addr *addr, const byte *ipv)
89{
90 addr->v4.s_addr = htonl((ipv[3]<<24) | (ipv[2]<<16) |
91 (ipv[1]<<8) | (ipv[0]));
92}
93
705b9b15 94static char *inet_rev_mkname(const struct sockaddr *sa, char *buf)
8a53cf7f 95{
705b9b15 96 unsigned long a = ntohl(CSIN(sa)->sin_addr.s_addr);
8a53cf7f
MW
97 int i;
98
99 for (i = 0; i < 4; i++) {
100 if (i) *buf++ = '.';
101 buf += sprintf(buf, "%d", (int)(a & 0xff));
102 a >>= 8;
103 }
104 return buf;
105}
106
9136cf0c 107const afinfo adns__inet_afinfo = {
8a53cf7f 108 AF_INET, 32, '.', 4, 3, adns_r_a,
705b9b15
MW
109 inet_sockaddr_to_inaddr, inet_sockaddr_equalp,
110 inet_prefix_mask, inet_guess_len, inet_matchp,
8a53cf7f 111 inet_rev_parsecomp, inet_rev_mkaddr, inet_rev_mkname
9136cf0c
MW
112};
113
114/*
115 * IPv6
116 */
117
118#define SIN6(sa) ((struct sockaddr_in6 *)(sa))
705b9b15 119#define CSIN6(sa) ((const struct sockaddr_in6 *)(sa))
9136cf0c
MW
120
121static void *inet6_sockaddr_to_inaddr(struct sockaddr *sa)
122 { return &SIN6(sa)->sin6_addr; }
123
705b9b15
MW
124static int inet6_sockaddr_equalp(const struct sockaddr *sa,
125 const struct sockaddr *sb)
126{
127 const struct sockaddr_in6 *sin6a = CSIN6(sa), *sin6b = CSIN6(sb);
128 return (memcmp(sin6a->sin6_addr.s6_addr,
129 sin6b->sin6_addr.s6_addr,
130 sizeof(sin6a->sin6_addr.s6_addr)) == 0 &&
131 sin6a->sin6_port == sin6b->sin6_port &&
132 sin6a->sin6_scope_id == sin6b->sin6_scope_id);
133}
134
9136cf0c
MW
135static void inet6_prefix_mask(int len, union gen_addr *mask)
136{
137 int i = len/8, j = len%8;
138 unsigned char *m = mask->v6.s6_addr;
139
140 assert(len < 128);
141 memset(m, 0xff, i);
142 if (j) m[i++] = (0xff << (8-j)) & 0xff;
143 memset(m + i, 0, 16-i);
144}
145
146static int inet6_guess_len(const union gen_addr *addr)
147 { return 64; }
148
149static int inet6_matchp(const union gen_addr *addr,
150 const union gen_addr *base,
151 const union gen_addr *mask)
152{
153 int i;
154 const char *a = addr->v6.s6_addr;
155 const char *b = base->v6.s6_addr;
156 const char *m = mask->v6.s6_addr;
157
158 for (i = 0; i < 16; i++)
159 if ((a[i] & m[i]) != b[i]) return 0;
160 return 1;
161}
162
8a53cf7f
MW
163static int inet6_rev_parsecomp(const char *p, size_t n)
164{
165 if (n != 1) return -1;
166 else if ('0' <= *p && *p <= '9') return *p - '0';
167 else if ('a' <= *p && *p <= 'f') return *p - 'a' + 10;
168 else if ('A' <= *p && *p <= 'F') return *p - 'a' + 10;
169 else return -1;
170}
171
172static void inet6_rev_mkaddr(union gen_addr *addr, const byte *ipv)
173{
174 unsigned char *a = addr->v6.s6_addr;
175 int i;
176
177 for (i = 0; i < 16; i++)
178 a[i] = (ipv[31-2*i] << 4) | (ipv[30-2*i] << 0);
179}
180
705b9b15 181static char *inet6_rev_mkname(const struct sockaddr *sa, char *buf)
8a53cf7f 182{
705b9b15 183 const unsigned char *a = CSIN6(sa)->sin6_addr.s6_addr + 16;
8a53cf7f
MW
184 unsigned c, y;
185 int i, j;
186
187 for (i = 0; i < 16; i++) {
188 c = *--a;
189 for (j = 0; j < 2; j++) {
190 if (i || j) *buf++ = '.';
191 y = c & 0xf;
192 if (y < 10) *buf++ = y + '0';
193 else *buf++ = y - 10 + 'a';
194 c >>= 4;
195 }
196 }
197 return buf;
198}
199
9136cf0c 200const afinfo adns__inet6_afinfo = {
8a53cf7f 201 AF_INET6, 128, ':', 32, 1, adns_r_aaaa,
705b9b15
MW
202 inet6_sockaddr_to_inaddr, inet6_sockaddr_equalp,
203 inet6_prefix_mask, inet6_guess_len, inet6_matchp,
8a53cf7f 204 inet6_rev_parsecomp, inet6_rev_mkaddr, inet6_rev_mkname
9136cf0c 205};