Commit | Line | Data |
---|---|---|
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 | ||
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 -------------------------------------------------*/ |