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 | ||
3b1bed1d MW |
33 | #define ADDRFAM_IPV4 AF_INET |
34 | #define NAME_IPV4 "IPv4" | |
35 | #define ADDRLEN_IPV4 32 | |
36 | ||
bf4d9761 MW |
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 | ||
3b1bed1d MW |
69 | #define ADDRFAM_IPV6 AF_INET6 |
70 | #define NAME_IPV6 "IPv6" | |
71 | #define ADDRLEN_IPV6 128 | |
72 | ||
bf4d9761 MW |
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 | ||
c3794524 | 117 | /* Answer whether the sockets SA and SB are equal. */ |
bf4d9761 MW |
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 | ||
c3794524 | 122 | /* Write a textual description of S to the string D. */ |
bf4d9761 MW |
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[] = { | |
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 }, | |
142 | ADDRTYPES(DEFOPS) | |
143 | { 0 } | |
144 | #undef DEFOPS | |
145 | }; | |
146 | ||
147 | /*----- That's all, folks -------------------------------------------------*/ |