Revision 05476c4d sysdep/bsd/sysio.h

View differences:

sysdep/bsd/sysio.h
1 1
/*
2
 *	BIRD Internet Routing Daemon -- NetBSD Multicasting and Network Includes
2
 *	BIRD Internet Routing Daemon -- BSD Multicasting and Network Includes
3 3
 *
4 4
 *	(c) 2004       Ondrej Filip <feela@network.cz>
5 5
 *
6 6
 *	Can be freely distributed and used under the terms of the GNU GPL.
7 7
 */
8 8

  
9
#include <net/if_dl.h>
10
#include <netinet/in_systm.h> // Workaround for some BSDs
11
#include <netinet/ip.h>
12

  
13

  
9 14
#ifdef __NetBSD__
10 15

  
11 16
#ifndef IP_RECVTTL
......
22 27
#define TCP_MD5SIG	TCP_SIGNATURE_ENABLE
23 28
#endif
24 29

  
25
#ifdef IPV6
26 30

  
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
}
31
#define SA_LEN(x) (x).sa.sa_len
33 32

  
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 33

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

  
64
/* BSD Multicast handling for IPv4 */
38
#define INIT_MREQ4(maddr,ifa) \
39
  { .imr_multiaddr = ipa_to_in4(maddr), .imr_interface = ipa_to_in4(ifa->addr->ip) }
65 40

  
66
static inline char *
67
sysio_setup_multicast(sock *s)
41
static inline int
42
sk_setup_multicast4(sock *s)
68 43
{
69
	struct in_addr m;
70
	u8 zero = 0;
71
	u8 ttl = s->ttl;
44
  struct in_addr ifa = ipa_to_in4(s->iface->addr->ip);
45
  u8 ttl = s->ttl;
46
  u8 n = 0;
72 47

  
73
	if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
74
		return "IP_MULTICAST_LOOP";
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");
75 51

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

  
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";
55
  if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &n, sizeof(n)) < 0)
56
    ERR("IP_MULTICAST_LOOP");
83 57

  
84
	return NULL;
58
  return 0;
85 59
}
86 60

  
87

  
88
static inline char *
89
sysio_join_group(sock *s, ip_addr maddr)
61
static inline int
62
sk_join_group4(sock *s, ip_addr maddr)
90 63
{
91
	struct ip_mreq mreq;
64
  struct ip_mreq mr = INIT_MREQ4(maddr, s->iface);
92 65

  
93
	bzero(&mreq, sizeof(mreq));
94
	set_inaddr(&mreq.imr_interface, s->iface->addr->ip);
95
	set_inaddr(&mreq.imr_multiaddr, maddr);
66
  if (setsockopt(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0)
67
    ERR("IP_ADD_MEMBERSHIP");
96 68

  
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;
69
  return 0;
102 70
}
103 71

  
104
static inline char *
105
sysio_leave_group(sock *s, ip_addr maddr)
72
static inline int
73
sk_leave_group4(sock *s, ip_addr maddr)
106 74
{
107
	struct ip_mreq mreq;
75
  struct ip_mreq mr = INIT_MREQ4(maddr, s->iface);
108 76

  
109
	bzero(&mreq, sizeof(mreq));
110
	set_inaddr(&mreq.imr_interface, s->iface->addr->ip);
111
	set_inaddr(&mreq.imr_multiaddr, maddr);
77
  if (setsockopt(s->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mr, sizeof(mr)) < 0)
78
    ERR("IP_ADD_MEMBERSHIP");
112 79

  
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;
80
  return 0;
118 81
}
119 82

  
120 83

  
121
/* BSD RX/TX packet info handling for IPv4 */
122
/* it uses IP_RECVDSTADDR / IP_RECVIF socket options instead of IP_PKTINFO */
84
/*
85
 *	BSD IPv4 packet control messages
86
 */
123 87

  
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))
88
/* It uses IP_RECVDSTADDR / IP_RECVIF socket options instead of IP_PKTINFO */
128 89

  
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";
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))
137 93

  
138
    if (setsockopt(s->fd, IPPROTO_IP, IP_RECVIF, &ok, sizeof(ok)) < 0)
139
      return "IP_RECVIF";
140
  }
94
static inline int
95
sk_request_cmsg4_pktinfo(sock *s)
96
{
97
  int y = 1;
141 98

  
142
  if ((s->flags & SKF_TTL_RX) &&
143
      (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0))
144
    return "IP_RECVTTL";
99
  if (setsockopt(s->fd, IPPROTO_IP, IP_RECVDSTADDR, &y, sizeof(y)) < 0)
100
    ERR("IP_RECVDSTADDR");
145 101

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

  
147
  return NULL;
105
  return 0;
148 106
}
149 107

  
150
static inline void
151
sysio_process_rx_cmsgs(sock *s, struct msghdr *msg)
108
static inline int
109
sk_request_cmsg4_ttl(sock *s)
152 110
{
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
  }
111
  int y = 1;
169 112

  
170
  if (s->flags & SKF_LADDR_RX)
171
  {
172
    s->laddr = IPA_NONE;
173
    s->lifindex = 0;
113
  if (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &y, sizeof(y)) < 0)
114
    ERR("IP_RECVTTL");
174 115

  
175
    if (ra)
176
      get_inaddr(&s->laddr, ra);
177
    if (ri)
178
      s->lifindex = ri->sdl_index;
179
  }
116
  return 0;
117
}
180 118

  
181
  if (s->flags & SKF_TTL_RX)
182
    s->ttl = ttl ? *ttl : -1;
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));
183 124

  
184
  // log(L_WARN "RX %I %d", s->laddr, s->lifindex);
125
  if (cm->cmsg_type == IP_RECVIF)
126
    s->lifindex = ((struct sockaddr_dl *) CMSG_DATA(cm))->sdl_index;
185 127
}
186 128

  
187
/* Unfortunately, IP_SENDSRCADDR does not work for raw IP sockets on BSD kernels */
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
}
188 135

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

  
192 141
#ifdef IP_SENDSRCADDR
193 142
  struct cmsghdr *cm;
194 143
  struct in_addr *sa;
......
202 151
  cm->cmsg_len = CMSG_LEN(sizeof(*sa));
203 152

  
204 153
  sa = (struct in_addr *) CMSG_DATA(cm);
205
  set_inaddr(sa, s->saddr);
154
  *sa = ipa_to_in4(s->saddr);
206 155

  
207 156
  msg->msg_controllen = cm->cmsg_len;
208 157
#endif
209 158
}
210 159

  
211

  
212 160
static void
213
fill_ip_header(sock *s, void *hdr, int dlen)
161
sk_prepare_ip_header(sock *s, void *hdr, int dlen)
214 162
{
215 163
  struct ip *ip = hdr;
216 164

  
......
222 170
  ip->ip_len = 20 + dlen;
223 171
  ip->ip_ttl = (s->ttl < 0) ? 64 : s->ttl;
224 172
  ip->ip_p = s->dport;
225
  set_inaddr(&ip->ip_src, s->saddr);
226
  set_inaddr(&ip->ip_dst, s->daddr);
173
  ip->ip_src = ipa_to_in4(s->saddr);
174
  ip->ip_dst = ipa_to_in4(s->daddr);
227 175

  
228 176
#ifdef __OpenBSD__
229 177
  /* OpenBSD expects ip_len in network order, other BSDs expect host order */
......
231 179
#endif
232 180
}
233 181

  
234
#endif
235 182

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

  
237
#include <netinet/tcp.h>
238 187
#ifndef TCP_KEYLEN_MAX
239 188
#define TCP_KEYLEN_MAX 80
240 189
#endif
......
248 197
 * management.
249 198
 */
250 199

  
251
static int
252
sk_set_md5_auth_int(sock *s, sockaddr *sa, char *passwd)
200
int
201
sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd)
253 202
{
254 203
  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 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
  }
281 221

  
282
#ifndef IPV6
222
  return 0;
223
}
283 224

  
284
static int
225
static inline int
285 226
sk_set_min_ttl4(sock *s, int ttl)
286 227
{
287 228
  if (setsockopt(s->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0)
288 229
  {
289 230
    if (errno == ENOPROTOOPT)
290
      log(L_ERR "Kernel does not support IPv4 TTL security");
231
      ERR_MSG("Kernel does not support IPv4 TTL security");
291 232
    else
292
      log(L_ERR "sk_set_min_ttl4: setsockopt: %m");
293

  
294
    return -1;
233
      ERR("IP_MINTTL");
295 234
  }
296 235

  
297 236
  return 0;
298 237
}
299 238

  
300
#else /* IPv6 */
301

  
302
static int
239
static inline int
303 240
sk_set_min_ttl6(sock *s, int ttl)
304 241
{
305
  log(L_ERR "IPv6 TTL security not supported");
306
  return -1;
242
  ERR_MSG("Kernel does not support IPv6 TTL security");
307 243
}
308 244

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

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

  
312 259
int sk_priority_control = -1;
313 260

  
314
static int
261
static inline int
315 262
sk_set_priority(sock *s, int prio UNUSED)
316 263
{
317
  log(L_WARN "Socket priority not supported");
318
  return -1;
264
  ERR_MSG("Socket priority not supported");
319 265
}

Also available in: Unified diff