Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / bsd / sysio.h @ 05476c4d

History | View | Annotate | Download (5.34 KB)

1
/*
2
 *        BIRD Internet Routing Daemon -- BSD 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
#include <net/if_dl.h>
10
#include <netinet/in_systm.h> // Workaround for some BSDs
11
#include <netinet/ip.h>
12

    
13

    
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

    
26
#ifdef __DragonFly__
27
#define TCP_MD5SIG        TCP_SIGNATURE_ENABLE
28
#endif
29

    
30

    
31
#define SA_LEN(x) (x).sa.sa_len
32

    
33

    
34
/*
35
 *        BSD IPv4 multicast syscalls
36
 */
37

    
38
#define INIT_MREQ4(maddr,ifa) \
39
  { .imr_multiaddr = ipa_to_in4(maddr), .imr_interface = ipa_to_in4(ifa->addr->ip) }
40

    
41
static inline int
42
sk_setup_multicast4(sock *s)
43
{
44
  struct in_addr ifa = ipa_to_in4(s->iface->addr->ip);
45
  u8 ttl = s->ttl;
46
  u8 n = 0;
47

    
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");
51

    
52
  if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
53
    ERR("IP_MULTICAST_TTL");
54

    
55
  if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &n, sizeof(n)) < 0)
56
    ERR("IP_MULTICAST_LOOP");
57

    
58
  return 0;
59
}
60

    
61
static inline int
62
sk_join_group4(sock *s, ip_addr maddr)
63
{
64
  struct ip_mreq mr = INIT_MREQ4(maddr, s->iface);
65

    
66
  if (setsockopt(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0)
67
    ERR("IP_ADD_MEMBERSHIP");
68

    
69
  return 0;
70
}
71

    
72
static inline int
73
sk_leave_group4(sock *s, ip_addr maddr)
74
{
75
  struct ip_mreq mr = INIT_MREQ4(maddr, s->iface);
76

    
77
  if (setsockopt(s->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mr, sizeof(mr)) < 0)
78
    ERR("IP_ADD_MEMBERSHIP");
79

    
80
  return 0;
81
}
82

    
83

    
84
/*
85
 *        BSD IPv4 packet control messages
86
 */
87

    
88
/* It uses IP_RECVDSTADDR / IP_RECVIF socket options instead of IP_PKTINFO */
89

    
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))
93

    
94
static inline int
95
sk_request_cmsg4_pktinfo(sock *s)
96
{
97
  int y = 1;
98

    
99
  if (setsockopt(s->fd, IPPROTO_IP, IP_RECVDSTADDR, &y, sizeof(y)) < 0)
100
    ERR("IP_RECVDSTADDR");
101

    
102
  if (setsockopt(s->fd, IPPROTO_IP, IP_RECVIF, &y, sizeof(y)) < 0)
103
    ERR("IP_RECVIF");
104

    
105
  return 0;
106
}
107

    
108
static inline int
109
sk_request_cmsg4_ttl(sock *s)
110
{
111
  int y = 1;
112

    
113
  if (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &y, sizeof(y)) < 0)
114
    ERR("IP_RECVTTL");
115

    
116
  return 0;
117
}
118

    
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));
124

    
125
  if (cm->cmsg_type == IP_RECVIF)
126
    s->lifindex = ((struct sockaddr_dl *) CMSG_DATA(cm))->sdl_index;
127
}
128

    
129
static inline void
130
sk_process_cmsg4_ttl(sock *s, struct cmsghdr *cm)
131
{
132
  if (cm->cmsg_type == IP_RECVTTL)
133
    s->rcv_ttl = * (unsigned char *) CMSG_DATA(cm);
134
}
135

    
136
static inline void
137
sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
138
{
139
  /* Unfortunately, IP_SENDSRCADDR does not work for raw IP sockets on BSD kernels */
140

    
141
#ifdef IP_SENDSRCADDR
142
  struct cmsghdr *cm;
143
  struct in_addr *sa;
144

    
145
  msg->msg_control = cbuf;
146
  msg->msg_controllen = cbuflen;
147

    
148
  cm = CMSG_FIRSTHDR(msg);
149
  cm->cmsg_level = IPPROTO_IP;
150
  cm->cmsg_type = IP_SENDSRCADDR;
151
  cm->cmsg_len = CMSG_LEN(sizeof(*sa));
152

    
153
  sa = (struct in_addr *) CMSG_DATA(cm);
154
  *sa = ipa_to_in4(s->saddr);
155

    
156
  msg->msg_controllen = cm->cmsg_len;
157
#endif
158
}
159

    
160
static void
161
sk_prepare_ip_header(sock *s, void *hdr, int dlen)
162
{
163
  struct ip *ip = hdr;
164

    
165
  bzero(ip, 20);
166

    
167
  ip->ip_v = 4;
168
  ip->ip_hl = 5;
169
  ip->ip_tos = (s->tos < 0) ? 0 : s->tos;
170
  ip->ip_len = 20 + dlen;
171
  ip->ip_ttl = (s->ttl < 0) ? 64 : s->ttl;
172
  ip->ip_p = s->dport;
173
  ip->ip_src = ipa_to_in4(s->saddr);
174
  ip->ip_dst = ipa_to_in4(s->daddr);
175

    
176
#ifdef __OpenBSD__
177
  /* OpenBSD expects ip_len in network order, other BSDs expect host order */
178
  ip->ip_len = htons(ip->ip_len);
179
#endif
180
}
181

    
182

    
183
/*
184
 *        Miscellaneous BSD socket syscalls
185
 */
186

    
187
#ifndef TCP_KEYLEN_MAX
188
#define TCP_KEYLEN_MAX 80
189
#endif
190
#ifndef TCP_SIG_SPI
191
#define TCP_SIG_SPI 0x1000
192
#endif
193

    
194
/* 
195
 * FIXME: Passwords has to be set by setkey(8) command. This is the same
196
 * behaviour like Quagga. We need to add code for SA/SP entries
197
 * management.
198
 */
199

    
200
int
201
sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd)
202
{
203
  int enable = 0;
204

    
205
  if (passwd && *passwd)
206
  {
207
    int len = strlen(passwd);
208
    enable = TCP_SIG_SPI;
209

    
210
    if (len > TCP_KEYLEN_MAX)
211
      ERR_MSG("MD5 password too long");
212
  }
213

    
214
  if (setsockopt(s->fd, IPPROTO_TCP, TCP_MD5SIG, &enable, sizeof(enable)) < 0)
215
  {
216
    if (errno == ENOPROTOOPT)
217
      ERR_MSG("Kernel does not support TCP MD5 signatures");
218
    else
219
      ERR("TCP_MD5SIG");
220
  }
221

    
222
  return 0;
223
}
224

    
225
static inline int
226
sk_set_min_ttl4(sock *s, int ttl)
227
{
228
  if (setsockopt(s->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0)
229
  {
230
    if (errno == ENOPROTOOPT)
231
      ERR_MSG("Kernel does not support IPv4 TTL security");
232
    else
233
      ERR("IP_MINTTL");
234
  }
235

    
236
  return 0;
237
}
238

    
239
static inline int
240
sk_set_min_ttl6(sock *s, int ttl)
241
{
242
  ERR_MSG("Kernel does not support IPv6 TTL security");
243
}
244

    
245
static inline int
246
sk_disable_mtu_disc4(sock *s)
247
{
248
  /* TODO: Set IP_DONTFRAG to 0 ? */
249
  return 0;
250
}
251

    
252
static inline int
253
sk_disable_mtu_disc6(sock *s)
254
{
255
  /* TODO: Set IPV6_DONTFRAG to 0 ? */
256
  return 0;
257
}
258

    
259
int sk_priority_control = -1;
260

    
261
static inline int
262
sk_set_priority(sock *s, int prio UNUSED)
263
{
264
  ERR_MSG("Socket priority not supported");
265
}