Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / bsd / sysio.h @ 48e5f32d

History | View | Annotate | Download (6.49 KB)

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
}