Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / bsd / sysio.h @ e348ef01

History | View | Annotate | Download (5.39 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 = * (byte *) 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
  int controllen = 0;
145

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

    
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));
153
  controllen += CMSG_SPACE(sizeof(*sa));
154

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

    
158
  msg->msg_controllen = controllen;
159
#endif
160
}
161

    
162
static void
163
sk_prepare_ip_header(sock *s, void *hdr, int dlen)
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;
175
  ip->ip_src = ipa_to_in4(s->saddr);
176
  ip->ip_dst = ipa_to_in4(s->daddr);
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
182
}
183

    
184

    
185
/*
186
 *        Miscellaneous BSD socket syscalls
187
 */
188

    
189
#ifndef TCP_KEYLEN_MAX
190
#define TCP_KEYLEN_MAX 80
191
#endif
192
#ifndef TCP_SIG_SPI
193
#define TCP_SIG_SPI 0x1000
194
#endif
195

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

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

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

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

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

    
224
  return 0;
225
}
226

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

    
238
  return 0;
239
}
240

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

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

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

    
261
int sk_priority_control = -1;
262

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