]> git.ipfire.org Git - thirdparty/bird.git/blob - sysdep/bsd/sysio.h
Many changes in I/O and OSPF sockets and packet handling.
[thirdparty/bird.git] / sysdep / bsd / sysio.h
1 /*
2 * BIRD Internet Routing Daemon -- NetBSD Multicasting and Network Includes
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
9 #ifdef __NetBSD__
10
11 #ifndef IP_RECVTTL
12 #define IP_RECVTTL 23
13 #endif
14
15 #ifndef IP_MINTTL
16 #define IP_MINTTL 24
17 #endif
18
19 #endif
20
21 #ifdef __DragonFly__
22 #define TCP_MD5SIG TCP_SIGNATURE_ENABLE
23 #endif
24
25 #ifdef IPV6
26
27 static inline void
28 set_inaddr(struct in6_addr * ia, ip_addr a)
29 {
30 ipa_hton(a);
31 memcpy(ia, &a, sizeof(a));
32 }
33
34 static inline void
35 get_inaddr(ip_addr *a, struct in6_addr *ia)
36 {
37 memcpy(a, ia, sizeof(*a));
38 ipa_ntoh(*a);
39 }
40
41
42 #else
43
44 #include <net/if.h>
45 #include <net/if_dl.h>
46 #include <netinet/in_systm.h> // Workaround for some BSDs
47 #include <netinet/ip.h>
48
49 static inline void
50 set_inaddr(struct in_addr * ia, ip_addr a)
51 {
52 ipa_hton(a);
53 memcpy(&ia->s_addr, &a, sizeof(a));
54 }
55
56 static inline void
57 get_inaddr(ip_addr *a, struct in_addr *ia)
58 {
59 memcpy(a, &ia->s_addr, sizeof(*a));
60 ipa_ntoh(*a);
61 }
62
63
64 /* BSD Multicast handling for IPv4 */
65
66 static inline char *
67 sysio_setup_multicast(sock *s)
68 {
69 struct in_addr m;
70 u8 zero = 0;
71 u8 ttl = s->ttl;
72
73 if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
74 return "IP_MULTICAST_LOOP";
75
76 if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
77 return "IP_MULTICAST_TTL";
78
79 /* This defines where should we send _outgoing_ multicasts */
80 set_inaddr(&m, s->iface->addr->ip);
81 if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_IF, &m, sizeof(m)) < 0)
82 return "IP_MULTICAST_IF";
83
84 return NULL;
85 }
86
87
88 static inline char *
89 sysio_join_group(sock *s, ip_addr maddr)
90 {
91 struct ip_mreq mreq;
92
93 bzero(&mreq, sizeof(mreq));
94 set_inaddr(&mreq.imr_interface, s->iface->addr->ip);
95 set_inaddr(&mreq.imr_multiaddr, maddr);
96
97 /* And this one sets interface for _receiving_ multicasts from */
98 if (setsockopt(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
99 return "IP_ADD_MEMBERSHIP";
100
101 return NULL;
102 }
103
104 static inline char *
105 sysio_leave_group(sock *s, ip_addr maddr)
106 {
107 struct ip_mreq mreq;
108
109 bzero(&mreq, sizeof(mreq));
110 set_inaddr(&mreq.imr_interface, s->iface->addr->ip);
111 set_inaddr(&mreq.imr_multiaddr, maddr);
112
113 /* And this one sets interface for _receiving_ multicasts from */
114 if (setsockopt(s->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
115 return "IP_DROP_MEMBERSHIP";
116
117 return NULL;
118 }
119
120
121 /* BSD RX/TX packet info handling for IPv4 */
122 /* it uses IP_RECVDSTADDR / IP_RECVIF socket options instead of IP_PKTINFO */
123
124 #define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in_addr)) + \
125 CMSG_SPACE(sizeof(struct sockaddr_dl)) + \
126 CMSG_SPACE(sizeof(char)))
127 #define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in_addr))
128
129 static char *
130 sysio_register_cmsgs(sock *s)
131 {
132 int ok = 1;
133 if (s->flags & SKF_LADDR_RX)
134 {
135 if (setsockopt(s->fd, IPPROTO_IP, IP_RECVDSTADDR, &ok, sizeof(ok)) < 0)
136 return "IP_RECVDSTADDR";
137
138 if (setsockopt(s->fd, IPPROTO_IP, IP_RECVIF, &ok, sizeof(ok)) < 0)
139 return "IP_RECVIF";
140 }
141
142 if ((s->flags & SKF_TTL_RX) &&
143 (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0))
144 return "IP_RECVTTL";
145
146
147 return NULL;
148 }
149
150 static inline void
151 sysio_process_rx_cmsgs(sock *s, struct msghdr *msg)
152 {
153 struct cmsghdr *cm;
154 struct in_addr *ra = NULL;
155 struct sockaddr_dl *ri = NULL;
156 unsigned char *ttl = NULL;
157
158 for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
159 {
160 if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVDSTADDR)
161 ra = (struct in_addr *) CMSG_DATA(cm);
162
163 if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVIF)
164 ri = (struct sockaddr_dl *) CMSG_DATA(cm);
165
166 if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVTTL)
167 ttl = (unsigned char *) CMSG_DATA(cm);
168 }
169
170 if (s->flags & SKF_LADDR_RX)
171 {
172 s->laddr = IPA_NONE;
173 s->lifindex = 0;
174
175 if (ra)
176 get_inaddr(&s->laddr, ra);
177 if (ri)
178 s->lifindex = ri->sdl_index;
179 }
180
181 if (s->flags & SKF_TTL_RX)
182 s->ttl = ttl ? *ttl : -1;
183
184 // log(L_WARN "RX %I %d", s->laddr, s->lifindex);
185 }
186
187 /* Unfortunately, IP_SENDSRCADDR does not work for raw IP sockets on BSD kernels */
188
189 static inline void
190 sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
191 {
192 #ifdef IP_SENDSRCADDR
193 struct cmsghdr *cm;
194 struct in_addr *sa;
195
196 msg->msg_control = cbuf;
197 msg->msg_controllen = cbuflen;
198
199 cm = CMSG_FIRSTHDR(msg);
200 cm->cmsg_level = IPPROTO_IP;
201 cm->cmsg_type = IP_SENDSRCADDR;
202 cm->cmsg_len = CMSG_LEN(sizeof(*sa));
203
204 sa = (struct in_addr *) CMSG_DATA(cm);
205 set_inaddr(sa, s->saddr);
206
207 msg->msg_controllen = cm->cmsg_len;
208 #endif
209 }
210
211
212 static void
213 fill_ip_header(sock *s, void *hdr, int dlen)
214 {
215 struct ip *ip = hdr;
216
217 bzero(ip, 20);
218
219 ip->ip_v = 4;
220 ip->ip_hl = 5;
221 ip->ip_tos = (s->tos < 0) ? 0 : s->tos;
222 ip->ip_len = 20 + dlen;
223 ip->ip_ttl = (s->ttl < 0) ? 64 : s->ttl;
224 ip->ip_p = s->dport;
225 set_inaddr(&ip->ip_src, s->saddr);
226 set_inaddr(&ip->ip_dst, s->daddr);
227
228 #ifdef __OpenBSD__
229 /* OpenBSD expects ip_len in network order, other BSDs expect host order */
230 ip->ip_len = htons(ip->ip_len);
231 #endif
232 }
233
234 #endif
235
236
237 #include <netinet/tcp.h>
238 #ifndef TCP_KEYLEN_MAX
239 #define TCP_KEYLEN_MAX 80
240 #endif
241 #ifndef TCP_SIG_SPI
242 #define TCP_SIG_SPI 0x1000
243 #endif
244
245 /*
246 * FIXME: Passwords has to be set by setkey(8) command. This is the same
247 * behaviour like Quagga. We need to add code for SA/SP entries
248 * management.
249 */
250
251 static int
252 sk_set_md5_auth_int(sock *s, sockaddr *sa, char *passwd)
253 {
254 int enable = 0;
255 if (passwd)
256 {
257 int len = strlen(passwd);
258
259 enable = len ? TCP_SIG_SPI : 0;
260
261 if (len > TCP_KEYLEN_MAX)
262 {
263 log(L_ERR "MD5 password too long");
264 return -1;
265 }
266 }
267
268 int rv = setsockopt(s->fd, IPPROTO_TCP, TCP_MD5SIG, &enable, sizeof(enable));
269
270 if (rv < 0)
271 {
272 if (errno == ENOPROTOOPT)
273 log(L_ERR "Kernel does not support TCP MD5 signatures");
274 else
275 log(L_ERR "sk_set_md5_auth_int: setsockopt: %m");
276 }
277
278 return rv;
279 }
280
281
282 #ifndef IPV6
283
284 static int
285 sk_set_min_ttl4(sock *s, int ttl)
286 {
287 if (setsockopt(s->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0)
288 {
289 if (errno == ENOPROTOOPT)
290 log(L_ERR "Kernel does not support IPv4 TTL security");
291 else
292 log(L_ERR "sk_set_min_ttl4: setsockopt: %m");
293
294 return -1;
295 }
296
297 return 0;
298 }
299
300 #else /* IPv6 */
301
302 static int
303 sk_set_min_ttl6(sock *s, int ttl)
304 {
305 log(L_ERR "IPv6 TTL security not supported");
306 return -1;
307 }
308
309 #endif
310
311
312 int sk_priority_control = -1;
313
314 static int
315 sk_set_priority(sock *s, int prio UNUSED)
316 {
317 log(L_WARN "Socket priority not supported");
318 return -1;
319 }