chiark / gitweb /
25211dfdfe0a014a3e58232f425e5fb4bc28c32a
[yaid] / addr.c
1 /* -*-c-*-
2  *
3  * Address-type specific functionality
4  *
5  * (c) 2012 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Yet Another Ident Daemon (YAID).
11  *
12  * YAID 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 of the License, or
15  * (at your option) any later version.
16  *
17  * YAID 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 YAID; if not, write to the Free Software Foundation,
24  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 /*----- Header files ------------------------------------------------------*/
28
29 #include "yaid.h"
30
31 /*----- IPv4 addresses ----------------------------------------------------*/
32
33 static int addreq_ipv4(const union addr *a, const union addr *b)
34   { return a->ipv4.s_addr == b->ipv4.s_addr; }
35
36 static int match_addrpat_ipv4(const struct addrpat *ap, const union addr *a)
37 {
38   unsigned m;
39
40   if (!ap->len) return (1);
41   m = htonl((MASK32 << (32 - ap->len)) & MASK32);
42   return (((ap->addr.ipv4.s_addr ^ a->ipv4.s_addr) & m) == 0);
43 }
44
45 static void socket_to_sockaddr_ipv4(const struct socket *s,
46                                     void *sa, size_t *ssz)
47 {
48   struct sockaddr_in *sin = sa;
49
50   sin->sin_family = AF_INET;
51   sin->sin_addr = s->addr.ipv4;
52   sin->sin_port = htons(s->port);
53   *ssz = sizeof(*sin);
54 }
55
56 static void sockaddr_to_addr_ipv4(const void *sa, union addr *a)
57   { const struct sockaddr_in *sin = sa; a->ipv4 = sin->sin_addr; }
58
59 static int init_listen_socket_ipv4(int fd) { return (0); }
60
61 static const union addr any_ipv4 = { .ipv4.s_addr = INADDR_ANY };
62
63 /*----- IPv6 addresses ----------------------------------------------------*/
64
65 static int addreq_ipv6(const union addr *a, const union addr *b)
66   { return !memcmp(a->ipv6.s6_addr, b->ipv6.s6_addr, 16); }
67
68 static int match_addrpat_ipv6(const struct addrpat *ap, const union addr *a)
69 {
70   unsigned i = 0, m, n = ap->len;
71
72   if (!n) return (1);
73   for (i = 0; n >= 8; i++, n -= 8)
74     if (ap->addr.ipv6.s6_addr[i] != a->ipv6.s6_addr[i]) return (0);
75   if (!n) return (1);
76   m = (MASK8 << (8 - n)) & MASK8;
77   return (((ap->addr.ipv6.s6_addr[i] ^ a->ipv6.s6_addr[i]) & m) == 0);
78 }
79
80 static void socket_to_sockaddr_ipv6(const struct socket *s,
81                                     void *sa, size_t *ssz)
82 {
83   struct sockaddr_in6 *sin6 = sa;
84
85   sin6->sin6_family = AF_INET6;
86   sin6->sin6_addr = s->addr.ipv6;
87   sin6->sin6_port = htons(s->port);
88   sin6->sin6_flowinfo = 0;
89   sin6->sin6_scope_id = 0;
90   *ssz = sizeof(*sin6);
91 }
92
93 static void sockaddr_to_addr_ipv6(const void *sa, union addr *a)
94   { const struct sockaddr_in6 *sin6 = sa; a->ipv6 = sin6->sin6_addr; }
95
96 static int init_listen_socket_ipv6(int fd)
97 {
98   int yes = 1;
99
100   if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)))
101     return (-1);
102   return (0);
103 }
104
105 static const union addr any_ipv6 = { .ipv6 = IN6ADDR_ANY_INIT };
106
107 /*----- General utilities -------------------------------------------------*/
108
109 int sockeq(const struct addrops *ao,
110            const struct socket *sa, const struct socket *sb)
111   { return (ao->addreq(&sa->addr, &sb->addr) && sa->port == sb->port); }
112
113 void dputsock(dstr *d, const struct addrops *ao, const struct socket *s)
114 {
115   char buf[ADDRLEN];
116
117   inet_ntop(ao->af, &s->addr, buf, sizeof(buf));
118   if (!s->port || ao->af != AF_INET6) dstr_puts(d, buf);
119   else { dstr_putc(d, '['); dstr_puts(d, buf); dstr_putc(d, ']'); }
120   if (s->port) dstr_putf(d, ":%d", s->port);
121 }
122
123 /*----- The operations table ----------------------------------------------*/
124
125 const struct addrops addroptab[] = {
126 #define DEFOPS(ty, TY, af, name, len)                                   \
127   { AF_##af, name, len, &any_##ty, &addrops_sys_##ty,                   \
128     addreq_##ty, match_addrpat_##ty,                                    \
129     socket_to_sockaddr_##ty, sockaddr_to_addr_##ty,                     \
130     init_listen_socket_##ty },
131 ADDRTYPES(DEFOPS)
132   { 0 }
133 #undef DEFOPS
134 };
135
136 /*----- That's all, folks -------------------------------------------------*/