summaryrefslogtreecommitdiff
path: root/sysdep/bsd/sysio.h
blob: df5e02367697998d003ed6ebda2cb694300ae277 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
/*
 *	BIRD Internet Routing Daemon -- BSD Multicasting and Network Includes
 *
 *	(c) 2004       Ondrej Filip <feela@network.cz>
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

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


#ifdef __NetBSD__

#ifndef IP_RECVTTL
#define IP_RECVTTL 23
#endif

#ifndef IP_MINTTL
#define IP_MINTTL 24
#endif

#endif

#ifdef __DragonFly__
#define TCP_MD5SIG	TCP_SIGNATURE_ENABLE
#endif


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


/*
 *	BSD IPv4 multicast syscalls
 */

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

static inline int
sk_setup_multicast4(sock *s)
{
  struct in_addr ifa = ipa_to_in4(s->iface->addr->ip);
  u8 ttl = s->ttl;
  u8 n = 0;

  /* This defines where should we send _outgoing_ multicasts */
  if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_IF, &ifa, sizeof(ifa)) < 0)
    ERR("IP_MULTICAST_IF");

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

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

  return 0;
}

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

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

  return 0;
}

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

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

  return 0;
}


/*
 *	BSD IPv4 packet control messages
 */

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

#define CMSG4_SPACE_PKTINFO (CMSG_SPACE(sizeof(struct in_addr)) + \
			     CMSG_SPACE(sizeof(struct sockaddr_dl)))
#define CMSG4_SPACE_TTL CMSG_SPACE(sizeof(char))

static inline int
sk_request_cmsg4_pktinfo(sock *s)
{
  int y = 1;

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

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

  return 0;
}

static inline int
sk_request_cmsg4_ttl(sock *s)
{
  int y = 1;

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

  return 0;
}

static inline void
sk_process_cmsg4_pktinfo(sock *s, struct cmsghdr *cm)
{
  if (cm->cmsg_type == IP_RECVDSTADDR)
    s->laddr = ipa_from_in4(* (struct in_addr *) CMSG_DATA(cm));

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

static inline void
sk_process_cmsg4_ttl(sock *s, struct cmsghdr *cm)
{
  if (cm->cmsg_type == IP_RECVTTL)
    s->rcv_ttl = * (unsigned char *) CMSG_DATA(cm);
}

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

#ifdef IP_SENDSRCADDR
  struct cmsghdr *cm;
  struct in_addr *sa;
  int controllen = 0;

  msg->msg_control = cbuf;
  msg->msg_controllen = cbuflen;

  cm = CMSG_FIRSTHDR(msg);
  cm->cmsg_level = IPPROTO_IP;
  cm->cmsg_type = IP_SENDSRCADDR;
  cm->cmsg_len = CMSG_LEN(sizeof(*sa));
  controllen += CMSG_SPACE(sizeof(*sa));

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

  msg->msg_controllen = controllen;
#endif
}

static void
sk_prepare_ip_header(sock *s, void *hdr, int dlen)
{
  struct ip *ip = hdr;

  bzero(ip, 20);

  ip->ip_v = 4;
  ip->ip_hl = 5;
  ip->ip_tos = (s->tos < 0) ? 0 : s->tos;
  ip->ip_len = 20 + dlen;
  ip->ip_ttl = (s->ttl < 0) ? 64 : s->ttl;
  ip->ip_p = s->dport;
  ip->ip_src = ipa_to_in4(s->saddr);
  ip->ip_dst = ipa_to_in4(s->daddr);

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


/*
 *	Miscellaneous BSD socket syscalls
 */

#ifndef TCP_KEYLEN_MAX
#define TCP_KEYLEN_MAX 80
#endif
#ifndef TCP_SIG_SPI
#define TCP_SIG_SPI 0x1000
#endif

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

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

  if (passwd && *passwd)
  {
    int len = strlen(passwd);
    enable = TCP_SIG_SPI;

    if (len > TCP_KEYLEN_MAX)
      ERR_MSG("MD5 password too long");
  }

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

  return 0;
}

static inline int
sk_set_min_ttl4(sock *s, int ttl)
{
  if (setsockopt(s->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0)
  {
    if (errno == ENOPROTOOPT)
      ERR_MSG("Kernel does not support IPv4 TTL security");
    else
      ERR("IP_MINTTL");
  }

  return 0;
}

static inline int
sk_set_min_ttl6(sock *s, int ttl)
{
  ERR_MSG("Kernel does not support IPv6 TTL security");
}

static inline int
sk_disable_mtu_disc4(sock *s)
{
  /* TODO: Set IP_DONTFRAG to 0 ? */
  return 0;
}

static inline int
sk_disable_mtu_disc6(sock *s)
{
  /* TODO: Set IPV6_DONTFRAG to 0 ? */
  return 0;
}

int sk_priority_control = -1;

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