Makefile.am: Tweak `silent-rules' machinery.
[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 #define ADDRFAM_IPV4 AF_INET
34 #define NAME_IPV4 "IPv4"
35 #define ADDRLEN_IPV4 32
36
37 static int addreq_ipv4(const union addr *a, const union addr *b)
38 { return a->ipv4.s_addr == b->ipv4.s_addr; }
39
40 static int match_addrpat_ipv4(const struct addrpat *ap, const union addr *a)
41 {
42 unsigned m;
43
44 if (!ap->len) return (1);
45 m = htonl((MASK32 << (32 - ap->len)) & MASK32);
46 return (((ap->addr.ipv4.s_addr ^ a->ipv4.s_addr) & m) == 0);
47 }
48
49 static void socket_to_sockaddr_ipv4(const struct socket *s,
50 void *sa, size_t *ssz)
51 {
52 struct sockaddr_in *sin = sa;
53
54 sin->sin_family = AF_INET;
55 sin->sin_addr = s->addr.ipv4;
56 sin->sin_port = htons(s->port);
57 *ssz = sizeof(*sin);
58 }
59
60 static void sockaddr_to_addr_ipv4(const void *sa, union addr *a)
61 { const struct sockaddr_in *sin = sa; a->ipv4 = sin->sin_addr; }
62
63 static int init_listen_socket_ipv4(int fd) { return (0); }
64
65 static const union addr any_ipv4 = { .ipv4.s_addr = INADDR_ANY };
66
67 /*----- IPv6 addresses ----------------------------------------------------*/
68
69 #define ADDRFAM_IPV6 AF_INET6
70 #define NAME_IPV6 "IPv6"
71 #define ADDRLEN_IPV6 128
72
73 static int addreq_ipv6(const union addr *a, const union addr *b)
74 { return !memcmp(a->ipv6.s6_addr, b->ipv6.s6_addr, 16); }
75
76 static int match_addrpat_ipv6(const struct addrpat *ap, const union addr *a)
77 {
78 unsigned i = 0, m, n = ap->len;
79
80 if (!n) return (1);
81 for (i = 0; n >= 8; i++, n -= 8)
82 if (ap->addr.ipv6.s6_addr[i] != a->ipv6.s6_addr[i]) return (0);
83 if (!n) return (1);
84 m = (MASK8 << (8 - n)) & MASK8;
85 return (((ap->addr.ipv6.s6_addr[i] ^ a->ipv6.s6_addr[i]) & m) == 0);
86 }
87
88 static void socket_to_sockaddr_ipv6(const struct socket *s,
89 void *sa, size_t *ssz)
90 {
91 struct sockaddr_in6 *sin6 = sa;
92
93 sin6->sin6_family = AF_INET6;
94 sin6->sin6_addr = s->addr.ipv6;
95 sin6->sin6_port = htons(s->port);
96 sin6->sin6_flowinfo = 0;
97 sin6->sin6_scope_id = 0;
98 *ssz = sizeof(*sin6);
99 }
100
101 static void sockaddr_to_addr_ipv6(const void *sa, union addr *a)
102 { const struct sockaddr_in6 *sin6 = sa; a->ipv6 = sin6->sin6_addr; }
103
104 static int init_listen_socket_ipv6(int fd)
105 {
106 int yes = 1;
107
108 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)))
109 return (-1);
110 return (0);
111 }
112
113 static const union addr any_ipv6 = { .ipv6 = IN6ADDR_ANY_INIT };
114
115 /*----- General utilities -------------------------------------------------*/
116
117 /* Answer whether the sockets SA and SB are equal. */
118 int sockeq(const struct addrops *ao,
119 const struct socket *sa, const struct socket *sb)
120 { return (ao->addreq(&sa->addr, &sb->addr) && sa->port == sb->port); }
121
122 /* Write a textual description of S to the string D. */
123 void dputsock(dstr *d, const struct addrops *ao, const struct socket *s)
124 {
125 char buf[ADDRLEN];
126
127 inet_ntop(ao->af, &s->addr, buf, sizeof(buf));
128 if (!s->port || ao->af != AF_INET6) dstr_puts(d, buf);
129 else { dstr_putc(d, '['); dstr_puts(d, buf); dstr_putc(d, ']'); }
130 if (s->port) dstr_putf(d, ":%d", s->port);
131 }
132
133 /*----- The operations table ----------------------------------------------*/
134
135 const struct addrops addroptab[] = {
136 #define DEFOPS(ty, TY) \
137 { ADDRFAM_##TY, NAME_##TY, ADDRLEN_##TY, \
138 &any_##ty, &addrops_sys_##ty, \
139 addreq_##ty, match_addrpat_##ty, \
140 socket_to_sockaddr_##ty, sockaddr_to_addr_##ty, \
141 init_listen_socket_##ty },
142 ADDRTYPES(DEFOPS)
143 { 0 }
144 #undef DEFOPS
145 };
146
147 /*----- That's all, folks -------------------------------------------------*/