]>
Commit | Line | Data |
---|---|---|
b1a1faba | 1 | /* |
05476c4d | 2 | * BIRD Internet Routing Daemon -- BSD Multicasting and Network Includes |
b1a1faba OF |
3 | * |
4 | * (c) 2004 Ondrej Filip <feela@network.cz> | |
5 | * | |
6 | * Can be freely distributed and used under the terms of the GNU GPL. | |
7 | */ | |
8 | ||
05476c4d OZ |
9 | #include <net/if_dl.h> |
10 | #include <netinet/in_systm.h> // Workaround for some BSDs | |
11 | #include <netinet/ip.h> | |
12 | ||
13 | ||
354496ac OZ |
14 | #ifdef __NetBSD__ |
15 | ||
16 | #ifndef IP_RECVTTL | |
17 | #define IP_RECVTTL 23 | |
18 | #endif | |
19 | ||
20 | #ifndef IP_MINTTL | |
21 | #define IP_MINTTL 24 | |
22 | #endif | |
23 | ||
24 | #endif | |
25 | ||
d760229a OF |
26 | #ifdef __DragonFly__ |
27 | #define TCP_MD5SIG TCP_SIGNATURE_ENABLE | |
28 | #endif | |
354496ac | 29 | |
b1a1faba | 30 | |
05476c4d | 31 | #define SA_LEN(x) (x).sa.sa_len |
353729f5 | 32 | |
b1a1faba | 33 | |
05476c4d OZ |
34 | /* |
35 | * BSD IPv4 multicast syscalls | |
36 | */ | |
353729f5 | 37 | |
05476c4d OZ |
38 | #define INIT_MREQ4(maddr,ifa) \ |
39 | { .imr_multiaddr = ipa_to_in4(maddr), .imr_interface = ipa_to_in4(ifa->addr->ip) } | |
353729f5 | 40 | |
05476c4d OZ |
41 | static inline int |
42 | sk_setup_multicast4(sock *s) | |
b1a1faba | 43 | { |
05476c4d OZ |
44 | struct in_addr ifa = ipa_to_in4(s->iface->addr->ip); |
45 | u8 ttl = s->ttl; | |
46 | u8 n = 0; | |
b1a1faba | 47 | |
05476c4d OZ |
48 | /* This defines where should we send _outgoing_ multicasts */ |
49 | if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_IF, &ifa, sizeof(ifa)) < 0) | |
50 | ERR("IP_MULTICAST_IF"); | |
b1a1faba | 51 | |
05476c4d OZ |
52 | if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) |
53 | ERR("IP_MULTICAST_TTL"); | |
f9c799a0 | 54 | |
05476c4d OZ |
55 | if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &n, sizeof(n)) < 0) |
56 | ERR("IP_MULTICAST_LOOP"); | |
b1a1faba | 57 | |
05476c4d | 58 | return 0; |
b1a1faba OF |
59 | } |
60 | ||
05476c4d OZ |
61 | static inline int |
62 | sk_join_group4(sock *s, ip_addr maddr) | |
b1a1faba | 63 | { |
05476c4d | 64 | struct ip_mreq mr = INIT_MREQ4(maddr, s->iface); |
b1a1faba | 65 | |
05476c4d OZ |
66 | if (setsockopt(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0) |
67 | ERR("IP_ADD_MEMBERSHIP"); | |
b1a1faba | 68 | |
05476c4d | 69 | return 0; |
f9c799a0 | 70 | } |
b1a1faba | 71 | |
05476c4d OZ |
72 | static inline int |
73 | sk_leave_group4(sock *s, ip_addr maddr) | |
f9c799a0 | 74 | { |
05476c4d | 75 | struct ip_mreq mr = INIT_MREQ4(maddr, s->iface); |
b1a1faba | 76 | |
05476c4d OZ |
77 | if (setsockopt(s->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mr, sizeof(mr)) < 0) |
78 | ERR("IP_ADD_MEMBERSHIP"); | |
f9c799a0 | 79 | |
05476c4d | 80 | return 0; |
b1a1faba OF |
81 | } |
82 | ||
353729f5 | 83 | |
05476c4d OZ |
84 | /* |
85 | * BSD IPv4 packet control messages | |
86 | */ | |
353729f5 | 87 | |
05476c4d | 88 | /* It uses IP_RECVDSTADDR / IP_RECVIF socket options instead of IP_PKTINFO */ |
353729f5 | 89 | |
05476c4d OZ |
90 | #define CMSG4_SPACE_PKTINFO (CMSG_SPACE(sizeof(struct in_addr)) + \ |
91 | CMSG_SPACE(sizeof(struct sockaddr_dl))) | |
92 | #define CMSG4_SPACE_TTL CMSG_SPACE(sizeof(char)) | |
70e212f9 | 93 | |
05476c4d OZ |
94 | static inline int |
95 | sk_request_cmsg4_pktinfo(sock *s) | |
96 | { | |
97 | int y = 1; | |
70e212f9 | 98 | |
05476c4d OZ |
99 | if (setsockopt(s->fd, IPPROTO_IP, IP_RECVDSTADDR, &y, sizeof(y)) < 0) |
100 | ERR("IP_RECVDSTADDR"); | |
353729f5 | 101 | |
05476c4d OZ |
102 | if (setsockopt(s->fd, IPPROTO_IP, IP_RECVIF, &y, sizeof(y)) < 0) |
103 | ERR("IP_RECVIF"); | |
353729f5 | 104 | |
05476c4d | 105 | return 0; |
353729f5 OZ |
106 | } |
107 | ||
05476c4d OZ |
108 | static inline int |
109 | sk_request_cmsg4_ttl(sock *s) | |
353729f5 | 110 | { |
05476c4d | 111 | int y = 1; |
70e212f9 | 112 | |
05476c4d OZ |
113 | if (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &y, sizeof(y)) < 0) |
114 | ERR("IP_RECVTTL"); | |
70e212f9 | 115 | |
05476c4d OZ |
116 | return 0; |
117 | } | |
70e212f9 | 118 | |
05476c4d OZ |
119 | static inline void |
120 | sk_process_cmsg4_pktinfo(sock *s, struct cmsghdr *cm) | |
121 | { | |
122 | if (cm->cmsg_type == IP_RECVDSTADDR) | |
123 | s->laddr = ipa_from_in4(* (struct in_addr *) CMSG_DATA(cm)); | |
353729f5 | 124 | |
05476c4d OZ |
125 | if (cm->cmsg_type == IP_RECVIF) |
126 | s->lifindex = ((struct sockaddr_dl *) CMSG_DATA(cm))->sdl_index; | |
353729f5 OZ |
127 | } |
128 | ||
05476c4d OZ |
129 | static inline void |
130 | sk_process_cmsg4_ttl(sock *s, struct cmsghdr *cm) | |
131 | { | |
132 | if (cm->cmsg_type == IP_RECVTTL) | |
e348ef01 | 133 | s->rcv_ttl = * (byte *) CMSG_DATA(cm); |
05476c4d | 134 | } |
48e5f32d OZ |
135 | |
136 | static inline void | |
05476c4d | 137 | sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) |
353729f5 | 138 | { |
05476c4d OZ |
139 | /* Unfortunately, IP_SENDSRCADDR does not work for raw IP sockets on BSD kernels */ |
140 | ||
48e5f32d | 141 | #ifdef IP_SENDSRCADDR |
353729f5 OZ |
142 | struct cmsghdr *cm; |
143 | struct in_addr *sa; | |
8945f73d | 144 | int controllen = 0; |
353729f5 | 145 | |
bed41728 OZ |
146 | msg->msg_control = cbuf; |
147 | msg->msg_controllen = cbuflen; | |
353729f5 | 148 | |
353729f5 OZ |
149 | cm = CMSG_FIRSTHDR(msg); |
150 | cm->cmsg_level = IPPROTO_IP; | |
151 | cm->cmsg_type = IP_SENDSRCADDR; | |
152 | cm->cmsg_len = CMSG_LEN(sizeof(*sa)); | |
8945f73d | 153 | controllen += CMSG_SPACE(sizeof(*sa)); |
353729f5 OZ |
154 | |
155 | sa = (struct in_addr *) CMSG_DATA(cm); | |
05476c4d | 156 | *sa = ipa_to_in4(s->saddr); |
353729f5 | 157 | |
8945f73d | 158 | msg->msg_controllen = controllen; |
48e5f32d OZ |
159 | #endif |
160 | } | |
161 | ||
48e5f32d | 162 | static void |
05476c4d | 163 | sk_prepare_ip_header(sock *s, void *hdr, int dlen) |
48e5f32d OZ |
164 | { |
165 | struct ip *ip = hdr; | |
166 | ||
167 | bzero(ip, 20); | |
168 | ||
169 | ip->ip_v = 4; | |
170 | ip->ip_hl = 5; | |
171 | ip->ip_tos = (s->tos < 0) ? 0 : s->tos; | |
172 | ip->ip_len = 20 + dlen; | |
173 | ip->ip_ttl = (s->ttl < 0) ? 64 : s->ttl; | |
174 | ip->ip_p = s->dport; | |
05476c4d OZ |
175 | ip->ip_src = ipa_to_in4(s->saddr); |
176 | ip->ip_dst = ipa_to_in4(s->daddr); | |
48e5f32d OZ |
177 | |
178 | #ifdef __OpenBSD__ | |
179 | /* OpenBSD expects ip_len in network order, other BSDs expect host order */ | |
180 | ip->ip_len = htons(ip->ip_len); | |
181 | #endif | |
353729f5 OZ |
182 | } |
183 | ||
2b70f074 | 184 | |
05476c4d OZ |
185 | /* |
186 | * Miscellaneous BSD socket syscalls | |
187 | */ | |
2b70f074 | 188 | |
2b70f074 OF |
189 | #ifndef TCP_KEYLEN_MAX |
190 | #define TCP_KEYLEN_MAX 80 | |
191 | #endif | |
a7baa098 | 192 | |
2b70f074 OF |
193 | #ifndef TCP_SIG_SPI |
194 | #define TCP_SIG_SPI 0x1000 | |
195 | #endif | |
196 | ||
a7baa098 OZ |
197 | #if defined(__FreeBSD__) |
198 | #define USE_MD5SIG_SETKEY | |
925aa149 | 199 | #include "sysdep/bsd/setkey.h" |
a7baa098 | 200 | #endif |
2b70f074 | 201 | |
05476c4d | 202 | int |
a7baa098 | 203 | sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, struct iface *ifa, char *passwd, int setkey UNUSED) |
2b70f074 | 204 | { |
a7baa098 OZ |
205 | #ifdef USE_MD5SIG_SETKEY |
206 | if (setkey) | |
207 | if (sk_set_md5_in_sasp_db(s, local, remote, ifa, passwd) < 0) | |
208 | return -1; | |
209 | #endif | |
05476c4d | 210 | |
a7baa098 | 211 | int enable = (passwd && *passwd) ? TCP_SIG_SPI : 0; |
05476c4d OZ |
212 | if (setsockopt(s->fd, IPPROTO_TCP, TCP_MD5SIG, &enable, sizeof(enable)) < 0) |
213 | { | |
214 | if (errno == ENOPROTOOPT) | |
215 | ERR_MSG("Kernel does not support TCP MD5 signatures"); | |
216 | else | |
217 | ERR("TCP_MD5SIG"); | |
218 | } | |
b1b19433 | 219 | |
05476c4d OZ |
220 | return 0; |
221 | } | |
b1b19433 | 222 | |
05476c4d | 223 | static inline int |
b1b19433 OZ |
224 | sk_set_min_ttl4(sock *s, int ttl) |
225 | { | |
226 | if (setsockopt(s->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0) | |
227 | { | |
228 | if (errno == ENOPROTOOPT) | |
05476c4d | 229 | ERR_MSG("Kernel does not support IPv4 TTL security"); |
b1b19433 | 230 | else |
05476c4d | 231 | ERR("IP_MINTTL"); |
b1b19433 OZ |
232 | } |
233 | ||
234 | return 0; | |
235 | } | |
236 | ||
05476c4d | 237 | static inline int |
b1b19433 OZ |
238 | sk_set_min_ttl6(sock *s, int ttl) |
239 | { | |
05476c4d | 240 | ERR_MSG("Kernel does not support IPv6 TTL security"); |
b1b19433 OZ |
241 | } |
242 | ||
05476c4d OZ |
243 | static inline int |
244 | sk_disable_mtu_disc4(sock *s) | |
245 | { | |
246 | /* TODO: Set IP_DONTFRAG to 0 ? */ | |
247 | return 0; | |
248 | } | |
b1b19433 | 249 | |
05476c4d OZ |
250 | static inline int |
251 | sk_disable_mtu_disc6(sock *s) | |
252 | { | |
253 | /* TODO: Set IPV6_DONTFRAG to 0 ? */ | |
254 | return 0; | |
255 | } | |
ef4a50be OZ |
256 | |
257 | int sk_priority_control = -1; | |
258 | ||
05476c4d | 259 | static inline int |
ef4a50be OZ |
260 | sk_set_priority(sock *s, int prio UNUSED) |
261 | { | |
05476c4d | 262 | ERR_MSG("Socket priority not supported"); |
ef4a50be | 263 | } |