Makefile.am: Tweak `silent-rules' machinery.
[yaid] / addr.c
CommitLineData
bf4d9761
MW
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
3b1bed1d
MW
33#define ADDRFAM_IPV4 AF_INET
34#define NAME_IPV4 "IPv4"
35#define ADDRLEN_IPV4 32
36
bf4d9761
MW
37static int addreq_ipv4(const union addr *a, const union addr *b)
38 { return a->ipv4.s_addr == b->ipv4.s_addr; }
39
40static 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
49static 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
60static void sockaddr_to_addr_ipv4(const void *sa, union addr *a)
61 { const struct sockaddr_in *sin = sa; a->ipv4 = sin->sin_addr; }
62
63static int init_listen_socket_ipv4(int fd) { return (0); }
64
65static const union addr any_ipv4 = { .ipv4.s_addr = INADDR_ANY };
66
67/*----- IPv6 addresses ----------------------------------------------------*/
68
3b1bed1d
MW
69#define ADDRFAM_IPV6 AF_INET6
70#define NAME_IPV6 "IPv6"
71#define ADDRLEN_IPV6 128
72
bf4d9761
MW
73static int addreq_ipv6(const union addr *a, const union addr *b)
74 { return !memcmp(a->ipv6.s6_addr, b->ipv6.s6_addr, 16); }
75
76static 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
88static 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
101static void sockaddr_to_addr_ipv6(const void *sa, union addr *a)
102 { const struct sockaddr_in6 *sin6 = sa; a->ipv6 = sin6->sin6_addr; }
103
104static 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
113static const union addr any_ipv6 = { .ipv6 = IN6ADDR_ANY_INIT };
114
115/*----- General utilities -------------------------------------------------*/
116
c3794524 117/* Answer whether the sockets SA and SB are equal. */
bf4d9761
MW
118int 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
c3794524 122/* Write a textual description of S to the string D. */
bf4d9761
MW
123void 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
135const struct addrops addroptab[] = {
3b1bed1d
MW
136#define DEFOPS(ty, TY) \
137 { ADDRFAM_##TY, NAME_##TY, ADDRLEN_##TY, \
138 &any_##ty, &addrops_sys_##ty, \
bf4d9761
MW
139 addreq_##ty, match_addrpat_##ty, \
140 socket_to_sockaddr_##ty, sockaddr_to_addr_##ty, \
141 init_listen_socket_##ty },
142ADDRTYPES(DEFOPS)
143 { 0 }
144#undef DEFOPS
145};
146
147/*----- That's all, folks -------------------------------------------------*/