Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (6.51 KB)

1 67ece6df Martin Mares
/*
2
 *        BIRD Internet Routing Daemon -- Linux Multicasting and Network Includes
3
 *
4 f380aa60 Martin Mares
 *        (c) 1998--2000 Martin Mares <mj@ucw.cz>
5 67ece6df Martin Mares
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8
9 e7b09e4a Ondrej Zajicek
#include <net/if.h>
10
11 67ece6df Martin Mares
#ifdef IPV6
12 a2867cd9 Martin Mares
13 84f07002 Martin Mares
#ifndef IPV6_UNICAST_HOPS
14
/* Needed on glibc 2.0 systems */
15 f380aa60 Martin Mares
#include <linux/in6.h>
16 84f07002 Martin Mares
#define CONFIG_IPV6_GLIBC_20
17 f380aa60 Martin Mares
#endif
18 67ece6df Martin Mares
19 a2867cd9 Martin Mares
static inline void
20
set_inaddr(struct in6_addr *ia, ip_addr a)
21
{
22
  ipa_hton(a);
23
  memcpy(ia, &a, sizeof(a));
24
}
25
26 353729f5 Ondrej Zajicek
static inline void
27
get_inaddr(ip_addr *a, struct in6_addr *ia)
28
{
29
  memcpy(a, ia, sizeof(*a));
30
  ipa_ntoh(*a);
31
}
32
33 e7b09e4a Ondrej Zajicek
#else
34 0e5aa966 Martin Mares
35 a2867cd9 Martin Mares
static inline void
36
set_inaddr(struct in_addr *ia, ip_addr a)
37
{
38
  ipa_hton(a);
39
  memcpy(&ia->s_addr, &a, sizeof(a));
40
}
41
42 353729f5 Ondrej Zajicek
static inline void
43
get_inaddr(ip_addr *a, struct in_addr *ia)
44
{
45
  memcpy(a, &ia->s_addr, sizeof(*a));
46
  ipa_ntoh(*a);
47
}
48
49 67ece6df Martin Mares
50
#ifndef HAVE_STRUCT_IP_MREQN
51
/* Several versions of glibc don't define this structure, so we have to do it ourselves */
52
struct ip_mreqn
53
{
54
        struct in_addr        imr_multiaddr;                /* IP multicast address of group */
55
        struct in_addr        imr_address;                /* local IP address of interface */
56
        int                imr_ifindex;                /* Interface index */
57
};
58
#endif
59
60 f9c799a0 Ondrej Zajicek
61 48e5f32d Ondrej Zajicek
static inline void fill_mreqn(struct ip_mreqn *m, ip_addr maddr, struct iface *ifa)
62 67ece6df Martin Mares
{
63 f9c799a0 Ondrej Zajicek
  bzero(m, sizeof(*m));
64
  m->imr_ifindex = ifa->index;
65
  set_inaddr(&m->imr_multiaddr, maddr);
66 67ece6df Martin Mares
}
67
68 f9c799a0 Ondrej Zajicek
static inline char *
69
sysio_setup_multicast(sock *s)
70 67ece6df Martin Mares
{
71 f1aceff5 Ondrej Zajicek
  struct ip_mreqn m;
72 f9c799a0 Ondrej Zajicek
  int zero = 0;
73 67ece6df Martin Mares
74 f9c799a0 Ondrej Zajicek
  if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
75
    return "IP_MULTICAST_LOOP";
76
77
  if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_TTL, &s->ttl, sizeof(s->ttl)) < 0)
78
    return "IP_MULTICAST_TTL";
79
80
  /* This defines where should we send _outgoing_ multicasts */
81 48e5f32d Ondrej Zajicek
  fill_mreqn(&m, IPA_NONE, s->iface);
82 f9c799a0 Ondrej Zajicek
  if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_IF, &m, sizeof(m)) < 0)
83
    return "IP_MULTICAST_IF";
84
85
  return NULL;
86
}
87
88
static inline char *
89
sysio_join_group(sock *s, ip_addr maddr)
90
{
91 f1aceff5 Ondrej Zajicek
  struct ip_mreqn m;
92 f9c799a0 Ondrej Zajicek
93 67ece6df Martin Mares
  /* And this one sets interface for _receiving_ multicasts from */
94 48e5f32d Ondrej Zajicek
  fill_mreqn(&m, maddr, s->iface);
95 f9c799a0 Ondrej Zajicek
  if (setsockopt(s->fd, SOL_IP, IP_ADD_MEMBERSHIP, &m, sizeof(m)) < 0)
96 67ece6df Martin Mares
    return "IP_ADD_MEMBERSHIP";
97 f9c799a0 Ondrej Zajicek
98
  return NULL;
99
}
100
101
static inline char *
102
sysio_leave_group(sock *s, ip_addr maddr)
103
{
104 f1aceff5 Ondrej Zajicek
  struct ip_mreqn m;
105 f9c799a0 Ondrej Zajicek
106
  /* And this one sets interface for _receiving_ multicasts from */
107 48e5f32d Ondrej Zajicek
  fill_mreqn(&m, maddr, s->iface);
108 f9c799a0 Ondrej Zajicek
  if (setsockopt(s->fd, SOL_IP, IP_DROP_MEMBERSHIP, &m, sizeof(m)) < 0)
109
    return "IP_DROP_MEMBERSHIP";
110
111 67ece6df Martin Mares
  return NULL;
112
}
113
114
#endif
115 d51aa281 Ondrej Zajicek
116 f9c799a0 Ondrej Zajicek
117 48e5f32d Ondrej Zajicek
/* For the case that we have older libc headers */
118 d51aa281 Ondrej Zajicek
/* Copied from Linux kernel file include/linux/tcp.h */
119
120
#ifndef TCP_MD5SIG
121
122
#define TCP_MD5SIG  14
123
#define TCP_MD5SIG_MAXKEYLEN 80
124
125
struct tcp_md5sig {
126 11ec0f1a Ondrej Zajicek
  struct  sockaddr_storage tcpm_addr;             /* address associated */
127 d51aa281 Ondrej Zajicek
  __u16   __tcpm_pad1;                            /* zero */
128
  __u16   tcpm_keylen;                            /* key length */
129
  __u32   __tcpm_pad2;                            /* zero */
130
  __u8    tcpm_key[TCP_MD5SIG_MAXKEYLEN];         /* key (binary) */
131
};
132
133
#endif
134 2b70f074 Ondrej Filip
135
static int
136
sk_set_md5_auth_int(sock *s, sockaddr *sa, char *passwd)
137
{
138
  struct tcp_md5sig md5;
139
140
  memset(&md5, 0, sizeof(md5));
141
  memcpy(&md5.tcpm_addr, (struct sockaddr *) sa, sizeof(*sa));
142
143
  if (passwd)
144
    {
145
      int len = strlen(passwd);
146
147
      if (len > TCP_MD5SIG_MAXKEYLEN)
148
        {
149
          log(L_ERR "MD5 password too long");
150
          return -1;
151
        }
152
153
      md5.tcpm_keylen = len;
154
      memcpy(&md5.tcpm_key, passwd, len);
155
    }
156
157 48e5f32d Ondrej Zajicek
  int rv = setsockopt(s->fd, SOL_TCP, TCP_MD5SIG, &md5, sizeof(md5));
158 2b70f074 Ondrej Filip
159
  if (rv < 0) 
160
    {
161
      if (errno == ENOPROTOOPT)
162
        log(L_ERR "Kernel does not support TCP MD5 signatures");
163
      else
164
        log(L_ERR "sk_set_md5_auth_int: setsockopt: %m");
165
    }
166
167
  return rv;
168
}
169 353729f5 Ondrej Zajicek
170
171
#ifndef IPV6
172
173
/* RX/TX packet info handling for IPv4 */
174
/* Mostly similar to standardized IPv6 code */
175
176 70e212f9 Ondrej Zajicek
#define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in_pktinfo)) + CMSG_SPACE(sizeof(int)))
177 353729f5 Ondrej Zajicek
#define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in_pktinfo))
178
179
static char *
180
sysio_register_cmsgs(sock *s)
181
{
182
  int ok = 1;
183 70e212f9 Ondrej Zajicek
184 353729f5 Ondrej Zajicek
  if ((s->flags & SKF_LADDR_RX) &&
185 48e5f32d Ondrej Zajicek
      (setsockopt(s->fd, SOL_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0))
186 353729f5 Ondrej Zajicek
    return "IP_PKTINFO";
187
188 70e212f9 Ondrej Zajicek
  if ((s->flags & SKF_TTL_RX) &&
189 48e5f32d Ondrej Zajicek
      (setsockopt(s->fd, SOL_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0))
190 70e212f9 Ondrej Zajicek
    return "IP_RECVTTL";
191
192 353729f5 Ondrej Zajicek
  return NULL;
193
}
194
195
static void
196
sysio_process_rx_cmsgs(sock *s, struct msghdr *msg)
197
{
198
  struct cmsghdr *cm;
199
  struct in_pktinfo *pi = NULL;
200 70e212f9 Ondrej Zajicek
  int *ttl = NULL;
201 353729f5 Ondrej Zajicek
202
  for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
203 70e212f9 Ondrej Zajicek
  {
204 48e5f32d Ondrej Zajicek
    if (cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_PKTINFO)
205 70e212f9 Ondrej Zajicek
      pi = (struct in_pktinfo *) CMSG_DATA(cm);
206
207 48e5f32d Ondrej Zajicek
    if (cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_TTL)
208 70e212f9 Ondrej Zajicek
      ttl = (int *) CMSG_DATA(cm);
209
  }
210
211
  if (s->flags & SKF_LADDR_RX)
212
  {
213
    if (pi)
214 353729f5 Ondrej Zajicek
    {
215 70e212f9 Ondrej Zajicek
      get_inaddr(&s->laddr, &pi->ipi_addr);
216
      s->lifindex = pi->ipi_ifindex;
217 353729f5 Ondrej Zajicek
    }
218 70e212f9 Ondrej Zajicek
    else
219 353729f5 Ondrej Zajicek
    {
220
      s->laddr = IPA_NONE;
221
      s->lifindex = 0;
222
    }
223 70e212f9 Ondrej Zajicek
  }
224
225
  if (s->flags & SKF_TTL_RX)
226
    s->ttl = ttl ? *ttl : -1;
227 353729f5 Ondrej Zajicek
228
  return;
229
}
230
231 bed41728 Ondrej Zajicek
static void
232
sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
233 353729f5 Ondrej Zajicek
{
234
  struct cmsghdr *cm;
235
  struct in_pktinfo *pi;
236
237 bed41728 Ondrej Zajicek
  msg->msg_control = cbuf;
238
  msg->msg_controllen = cbuflen;
239 353729f5 Ondrej Zajicek
240
  cm = CMSG_FIRSTHDR(msg);
241 48e5f32d Ondrej Zajicek
  cm->cmsg_level = SOL_IP;
242 353729f5 Ondrej Zajicek
  cm->cmsg_type = IP_PKTINFO;
243
  cm->cmsg_len = CMSG_LEN(sizeof(*pi));
244
245
  pi = (struct in_pktinfo *) CMSG_DATA(cm);
246
  pi->ipi_ifindex = s->iface ? s->iface->index : 0;
247 48e5f32d Ondrej Zajicek
  set_inaddr(&pi->ipi_spec_dst, s->saddr);
248
  set_inaddr(&pi->ipi_addr, IPA_NONE);
249 353729f5 Ondrej Zajicek
250
  msg->msg_controllen = cm->cmsg_len;
251
}
252 48e5f32d Ondrej Zajicek
253 646b24d9 Ondrej Zajicek
254 353729f5 Ondrej Zajicek
#endif
255 b1b19433 Ondrej Zajicek
256
257
#ifndef IP_MINTTL
258
#define IP_MINTTL 21
259
#endif
260
261
#ifndef IPV6_MINHOPCOUNT
262
#define IPV6_MINHOPCOUNT 73
263
#endif
264
265
266
#ifndef IPV6
267
268
static int
269
sk_set_min_ttl4(sock *s, int ttl)
270
{
271 48e5f32d Ondrej Zajicek
  if (setsockopt(s->fd, SOL_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0)
272 b1b19433 Ondrej Zajicek
  {
273
    if (errno == ENOPROTOOPT)
274
      log(L_ERR "Kernel does not support IPv4 TTL security");
275
    else
276
      log(L_ERR "sk_set_min_ttl4: setsockopt: %m");
277
278
    return -1;
279
  }
280
281
  return 0;
282
}
283
284
#else
285
286
static int
287
sk_set_min_ttl6(sock *s, int ttl)
288
{
289 48e5f32d Ondrej Zajicek
  if (setsockopt(s->fd, SOL_IPV6, IPV6_MINHOPCOUNT, &ttl, sizeof(ttl)) < 0)
290 b1b19433 Ondrej Zajicek
  {
291
    if (errno == ENOPROTOOPT)
292
      log(L_ERR "Kernel does not support IPv6 TTL security");
293
    else
294 47c447c4 Ondrej Zajicek
      log(L_ERR "sk_set_min_ttl6: setsockopt: %m");
295 b1b19433 Ondrej Zajicek
296
    return -1;
297
  }
298
299
  return 0;
300
}
301
302
#endif
303 ef4a50be Ondrej Zajicek
304
305
#ifndef IPV6_TCLASS
306
#define IPV6_TCLASS 67
307
#endif
308
309
int sk_priority_control = 7;
310
311
static int
312
sk_set_priority(sock *s, int prio)
313
{
314
  if (setsockopt(s->fd, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)) < 0)
315
  {
316
    log(L_WARN "sk_set_priority: setsockopt: %m");
317
    return -1;
318
  }
319
320
  return 0;
321
}