Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (6.51 KB)

1
/*
2
 *        BIRD Internet Routing Daemon -- Linux Multicasting and Network Includes
3
 *
4
 *        (c) 1998--2000 Martin Mares <mj@ucw.cz>
5
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8

    
9
#include <net/if.h>
10

    
11
#ifdef IPV6
12

    
13
#ifndef IPV6_UNICAST_HOPS
14
/* Needed on glibc 2.0 systems */
15
#include <linux/in6.h>
16
#define CONFIG_IPV6_GLIBC_20
17
#endif
18

    
19
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
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
#else
34

    
35
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
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

    
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

    
61
static inline void fill_mreqn(struct ip_mreqn *m, ip_addr maddr, struct iface *ifa)
62
{
63
  bzero(m, sizeof(*m));
64
  m->imr_ifindex = ifa->index;
65
  set_inaddr(&m->imr_multiaddr, maddr);
66
}
67

    
68
static inline char *
69
sysio_setup_multicast(sock *s)
70
{
71
  struct ip_mreqn m;
72
  int zero = 0;
73

    
74
  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
  fill_mreqn(&m, IPA_NONE, s->iface);
82
  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
  struct ip_mreqn m;
92

    
93
  /* And this one sets interface for _receiving_ multicasts from */
94
  fill_mreqn(&m, maddr, s->iface);
95
  if (setsockopt(s->fd, SOL_IP, IP_ADD_MEMBERSHIP, &m, sizeof(m)) < 0)
96
    return "IP_ADD_MEMBERSHIP";
97

    
98
  return NULL;
99
}
100

    
101
static inline char *
102
sysio_leave_group(sock *s, ip_addr maddr)
103
{
104
  struct ip_mreqn m;
105

    
106
  /* And this one sets interface for _receiving_ multicasts from */
107
  fill_mreqn(&m, maddr, s->iface);
108
  if (setsockopt(s->fd, SOL_IP, IP_DROP_MEMBERSHIP, &m, sizeof(m)) < 0)
109
    return "IP_DROP_MEMBERSHIP";
110

    
111
  return NULL;
112
}
113

    
114
#endif
115

    
116

    
117
/* For the case that we have older libc headers */
118
/* 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
  struct  sockaddr_storage tcpm_addr;             /* address associated */
127
  __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

    
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
  int rv = setsockopt(s->fd, SOL_TCP, TCP_MD5SIG, &md5, sizeof(md5));
158

    
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

    
170

    
171
#ifndef IPV6
172

    
173
/* RX/TX packet info handling for IPv4 */
174
/* Mostly similar to standardized IPv6 code */
175

    
176
#define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in_pktinfo)) + CMSG_SPACE(sizeof(int)))
177
#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

    
184
  if ((s->flags & SKF_LADDR_RX) &&
185
      (setsockopt(s->fd, SOL_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0))
186
    return "IP_PKTINFO";
187

    
188
  if ((s->flags & SKF_TTL_RX) &&
189
      (setsockopt(s->fd, SOL_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0))
190
    return "IP_RECVTTL";
191

    
192
  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
  int *ttl = NULL;
201

    
202
  for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
203
  {
204
    if (cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_PKTINFO)
205
      pi = (struct in_pktinfo *) CMSG_DATA(cm);
206

    
207
    if (cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_TTL)
208
      ttl = (int *) CMSG_DATA(cm);
209
  }
210

    
211
  if (s->flags & SKF_LADDR_RX)
212
  {
213
    if (pi)
214
    {
215
      get_inaddr(&s->laddr, &pi->ipi_addr);
216
      s->lifindex = pi->ipi_ifindex;
217
    }
218
    else
219
    {
220
      s->laddr = IPA_NONE;
221
      s->lifindex = 0;
222
    }
223
  }
224

    
225
  if (s->flags & SKF_TTL_RX)
226
    s->ttl = ttl ? *ttl : -1;
227

    
228
  return;
229
}
230

    
231
static void
232
sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
233
{
234
  struct cmsghdr *cm;
235
  struct in_pktinfo *pi;
236

    
237
  msg->msg_control = cbuf;
238
  msg->msg_controllen = cbuflen;
239

    
240
  cm = CMSG_FIRSTHDR(msg);
241
  cm->cmsg_level = SOL_IP;
242
  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
  set_inaddr(&pi->ipi_spec_dst, s->saddr);
248
  set_inaddr(&pi->ipi_addr, IPA_NONE);
249

    
250
  msg->msg_controllen = cm->cmsg_len;
251
}
252

    
253

    
254
#endif
255

    
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
  if (setsockopt(s->fd, SOL_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0)
272
  {
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
  if (setsockopt(s->fd, SOL_IPV6, IPV6_MINHOPCOUNT, &ttl, sizeof(ttl)) < 0)
290
  {
291
    if (errno == ENOPROTOOPT)
292
      log(L_ERR "Kernel does not support IPv6 TTL security");
293
    else
294
      log(L_ERR "sk_set_min_ttl6: setsockopt: %m");
295

    
296
    return -1;
297
  }
298

    
299
  return 0;
300
}
301

    
302
#endif
303

    
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
}