src/: Support IPv6 addresses in `sortlist'.
[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 };