Revision 05476c4d sysdep/linux/sysio.h

View differences:

sysdep/linux/sysio.h
6 6
 *	Can be freely distributed and used under the terms of the GNU GPL.
7 7
 */
8 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 9

  
50 10
#ifndef HAVE_STRUCT_IP_MREQN
51 11
/* Several versions of glibc don't define this structure, so we have to do it ourselves */
52 12
struct ip_mreqn
53 13
{
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 */
14
  struct in_addr imr_multiaddr;			/* IP multicast address of group */
15
  struct in_addr imr_address;			/* local IP address of interface */
16
  int		 imr_ifindex;			/* Interface index */
57 17
};
58 18
#endif
59 19

  
20
#ifndef IP_MINTTL
21
#define IP_MINTTL 21
22
#endif
60 23

  
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
}
24
#ifndef IPV6_TCLASS
25
#define IPV6_TCLASS 67
26
#endif
67 27

  
68
static inline char *
69
sysio_setup_multicast(sock *s)
70
{
71
  struct ip_mreqn m;
72
  int zero = 0;
28
#ifndef IPV6_MINHOPCOUNT
29
#define IPV6_MINHOPCOUNT 73
30
#endif
73 31

  
74
  if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
75
    return "IP_MULTICAST_LOOP";
76 32

  
77
  if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_TTL, &s->ttl, sizeof(s->ttl)) < 0)
78
    return "IP_MULTICAST_TTL";
33
#ifndef TCP_MD5SIG
79 34

  
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";
35
#define TCP_MD5SIG  14
36
#define TCP_MD5SIG_MAXKEYLEN 80
84 37

  
85
  return NULL;
86
}
38
struct tcp_md5sig {
39
  struct  sockaddr_storage tcpm_addr;             /* address associated */
40
  u16   __tcpm_pad1;                              /* zero */
41
  u16   tcpm_keylen;                              /* key length */
42
  u32   __tcpm_pad2;                              /* zero */
43
  u8    tcpm_key[TCP_MD5SIG_MAXKEYLEN];           /* key (binary) */
44
};
87 45

  
88
static inline char *
89
sysio_join_group(sock *s, ip_addr maddr)
90
{
91
  struct ip_mreqn m;
46
#endif
92 47

  
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 48

  
98
  return NULL;
99
}
49
/* Linux does not care if sa_len is larger than needed */
50
#define SA_LEN(x) sizeof(sockaddr)
100 51

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

  
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";
53
/*
54
 *	Linux IPv4 multicast syscalls
55
 */
110 56

  
111
  return NULL;
112
}
57
#define INIT_MREQ4(maddr,ifa) \
58
  { .imr_multiaddr = ipa_to_in4(maddr), .imr_ifindex = ifa->index }
113 59

  
114
#endif
60
static inline int
61
sk_setup_multicast4(sock *s)
62
{
63
  struct ip_mreqn mr = { .imr_ifindex = s->iface->index };
64
  int ttl = s->ttl;
65
  int n = 0;
115 66

  
67
  /* This defines where should we send _outgoing_ multicasts */
68
  if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_IF, &mr, sizeof(mr)) < 0)
69
    ERR("IP_MULTICAST_IF");
116 70

  
117
/* For the case that we have older libc headers */
118
/* Copied from Linux kernel file include/linux/tcp.h */
71
  if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
72
    ERR("IP_MULTICAST_TTL");
119 73

  
120
#ifndef TCP_MD5SIG
74
  if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_LOOP, &n, sizeof(n)) < 0)
75
    ERR("IP_MULTICAST_LOOP");
121 76

  
122
#define TCP_MD5SIG  14
123
#define TCP_MD5SIG_MAXKEYLEN 80
77
  return 0;
78
}
124 79

  
125
#include <linux/types.h>
80
static inline int
81
sk_join_group4(sock *s, ip_addr maddr)
82
{
83
  struct ip_mreqn mr = INIT_MREQ4(maddr, s->iface);
126 84

  
127
struct tcp_md5sig {
128
  struct  sockaddr_storage tcpm_addr;             /* address associated */
129
  __u16   __tcpm_pad1;                            /* zero */
130
  __u16   tcpm_keylen;                            /* key length */
131
  __u32   __tcpm_pad2;                            /* zero */
132
  __u8    tcpm_key[TCP_MD5SIG_MAXKEYLEN];         /* key (binary) */
133
};
85
  if (setsockopt(s->fd, SOL_IP, IP_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0)
86
    ERR("IP_ADD_MEMBERSHIP");
134 87

  
135
#endif
88
  return 0;
89
}
136 90

  
137
static int
138
sk_set_md5_auth_int(sock *s, sockaddr *sa, char *passwd)
91
static inline int
92
sk_leave_group4(sock *s, ip_addr maddr)
139 93
{
140
  struct tcp_md5sig md5;
94
  struct ip_mreqn mr = INIT_MREQ4(maddr, s->iface);
141 95

  
142
  memset(&md5, 0, sizeof(md5));
143
  memcpy(&md5.tcpm_addr, (struct sockaddr *) sa, sizeof(*sa));
96
  if (setsockopt(s->fd, SOL_IP, IP_DROP_MEMBERSHIP, &mr, sizeof(mr)) < 0)
97
    ERR("IP_DROP_MEMBERSHIP");
144 98

  
145
  if (passwd)
146
    {
147
      int len = strlen(passwd);
148

  
149
      if (len > TCP_MD5SIG_MAXKEYLEN)
150
	{
151
	  log(L_ERR "MD5 password too long");
152
	  return -1;
153
	}
154

  
155
      md5.tcpm_keylen = len;
156
      memcpy(&md5.tcpm_key, passwd, len);
157
    }
158

  
159
  int rv = setsockopt(s->fd, SOL_TCP, TCP_MD5SIG, &md5, sizeof(md5));
160

  
161
  if (rv < 0) 
162
    {
163
      if (errno == ENOPROTOOPT)
164
	log(L_ERR "Kernel does not support TCP MD5 signatures");
165
      else
166
	log(L_ERR "sk_set_md5_auth_int: setsockopt: %m");
167
    }
168

  
169
  return rv;
99
  return 0;
170 100
}
171 101

  
172 102

  
173
#ifndef IPV6
103
/*
104
 *	Linux IPv4 packet control messages
105
 */
174 106

  
175
/* RX/TX packet info handling for IPv4 */
176 107
/* Mostly similar to standardized IPv6 code */
177 108

  
178
#define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in_pktinfo)) + CMSG_SPACE(sizeof(int)))
179
#define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in_pktinfo))
109
#define CMSG4_SPACE_PKTINFO CMSG_SPACE(sizeof(struct in_pktinfo))
110
#define CMSG4_SPACE_TTL CMSG_SPACE(sizeof(int))
180 111

  
181
static char *
182
sysio_register_cmsgs(sock *s)
112
static inline int
113
sk_request_cmsg4_pktinfo(sock *s)
183 114
{
184
  int ok = 1;
115
  int y = 1;
185 116

  
186
  if ((s->flags & SKF_LADDR_RX) &&
187
      (setsockopt(s->fd, SOL_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0))
188
    return "IP_PKTINFO";
117
  if (setsockopt(s->fd, SOL_IP, IP_PKTINFO, &y, sizeof(y)) < 0)
118
    ERR("IP_PKTINFO");
189 119

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

  
194
  return NULL;
120
  return 0;
195 121
}
196 122

  
197
static void
198
sysio_process_rx_cmsgs(sock *s, struct msghdr *msg)
123
static inline int
124
sk_request_cmsg4_ttl(sock *s)
199 125
{
200
  struct cmsghdr *cm;
201
  struct in_pktinfo *pi = NULL;
202
  int *ttl = NULL;
126
  int y = 1;
203 127

  
204
  for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
205
  {
206
    if (cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_PKTINFO)
207
      pi = (struct in_pktinfo *) CMSG_DATA(cm);
128
  if (setsockopt(s->fd, SOL_IP, IP_RECVTTL, &y, sizeof(y)) < 0)
129
    ERR("IP_RECVTTL");
208 130

  
209
    if (cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_TTL)
210
      ttl = (int *) CMSG_DATA(cm);
211
  }
131
  return 0;
132
}
212 133

  
213
  if (s->flags & SKF_LADDR_RX)
134
static inline void
135
sk_process_cmsg4_pktinfo(sock *s, struct cmsghdr *cm)
136
{
137
  if (cm->cmsg_type == IP_PKTINFO)
214 138
  {
215
    if (pi)
216
    {
217
      get_inaddr(&s->laddr, &pi->ipi_addr);
218
      s->lifindex = pi->ipi_ifindex;
219
    }
220
    else
221
    {
222
      s->laddr = IPA_NONE;
223
      s->lifindex = 0;
224
    }
139
    struct in_pktinfo *pi = (struct in_pktinfo *) CMSG_DATA(cm);
140
    s->laddr = ipa_from_in4(pi->ipi_addr);
141
    s->lifindex = pi->ipi_ifindex;
225 142
  }
143
}
226 144

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

  
230
  return;
145
static inline void
146
sk_process_cmsg4_ttl(sock *s, struct cmsghdr *cm)
147
{
148
  if (cm->cmsg_type == IP_TTL)
149
    s->rcv_ttl = * (int *) CMSG_DATA(cm);
231 150
}
232 151

  
233
static void
234
sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
152
static inline void
153
sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
235 154
{
236 155
  struct cmsghdr *cm;
237 156
  struct in_pktinfo *pi;
......
246 165

  
247 166
  pi = (struct in_pktinfo *) CMSG_DATA(cm);
248 167
  pi->ipi_ifindex = s->iface ? s->iface->index : 0;
249
  set_inaddr(&pi->ipi_spec_dst, s->saddr);
250
  set_inaddr(&pi->ipi_addr, IPA_NONE);
168
  pi->ipi_spec_dst = ipa_to_in4(s->saddr);
169
  pi->ipi_addr = ipa_to_in4(IPA_NONE);
251 170

  
252 171
  msg->msg_controllen = cm->cmsg_len;
253 172
}
254 173

  
255 174

  
256
#endif
175
/*
176
 *	Miscellaneous Linux socket syscalls
177
 */
257 178

  
179
int
180
sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd)
181
{
182
  struct tcp_md5sig md5;
258 183

  
259
#ifndef IP_MINTTL
260
#define IP_MINTTL 21
261
#endif
184
  memset(&md5, 0, sizeof(md5));
185
  sockaddr_fill((sockaddr *) &md5.tcpm_addr, s->af, a, ifa, 0);
262 186

  
263
#ifndef IPV6_MINHOPCOUNT
264
#define IPV6_MINHOPCOUNT 73
265
#endif
187
  if (passwd)
188
  {
189
    int len = strlen(passwd);
190

  
191
    if (len > TCP_MD5SIG_MAXKEYLEN)
192
      ERR_MSG("MD5 password too long");
266 193

  
194
    md5.tcpm_keylen = len;
195
    memcpy(&md5.tcpm_key, passwd, len);
196
  }
197

  
198
  if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG, &md5, sizeof(md5)) < 0)
199
  {
200
    if (errno == ENOPROTOOPT)
201
      ERR_MSG("Kernel does not support TCP MD5 signatures");
202
    else
203
      ERR("TCP_MD5SIG");
204
  }
267 205

  
268
#ifndef IPV6
206
  return 0;
207
}
269 208

  
270
static int
209
static inline int
271 210
sk_set_min_ttl4(sock *s, int ttl)
272 211
{
273 212
  if (setsockopt(s->fd, SOL_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0)
274 213
  {
275 214
    if (errno == ENOPROTOOPT)
276
      log(L_ERR "Kernel does not support IPv4 TTL security");
215
      ERR_MSG("Kernel does not support IPv4 TTL security");
277 216
    else
278
      log(L_ERR "sk_set_min_ttl4: setsockopt: %m");
279

  
280
    return -1;
217
      ERR("IP_MINTTL");
281 218
  }
282 219

  
283 220
  return 0;
284 221
}
285 222

  
286
#else
287

  
288
static int
223
static inline int
289 224
sk_set_min_ttl6(sock *s, int ttl)
290 225
{
291 226
  if (setsockopt(s->fd, SOL_IPV6, IPV6_MINHOPCOUNT, &ttl, sizeof(ttl)) < 0)
292 227
  {
293 228
    if (errno == ENOPROTOOPT)
294
      log(L_ERR "Kernel does not support IPv6 TTL security");
229
      ERR_MSG("Kernel does not support IPv6 TTL security");
295 230
    else
296
      log(L_ERR "sk_set_min_ttl6: setsockopt: %m");
297

  
298
    return -1;
231
      ERR("IPV6_MINHOPCOUNT");
299 232
  }
300 233

  
301 234
  return 0;
302 235
}
303 236

  
304
#endif
237
static inline int
238
sk_disable_mtu_disc4(sock *s)
239
{
240
  int dont = IP_PMTUDISC_DONT;
305 241

  
242
  if (setsockopt(s->fd, SOL_IP, IP_MTU_DISCOVER, &dont, sizeof(dont)) < 0)
243
    ERR("IP_MTU_DISCOVER");
306 244

  
307
#ifndef IPV6_TCLASS
308
#define IPV6_TCLASS 67
309
#endif
245
  return 0;
246
}
247

  
248
static inline int
249
sk_disable_mtu_disc6(sock *s)
250
{
251
  int dont = IPV6_PMTUDISC_DONT;
252

  
253
  if (setsockopt(s->fd, SOL_IPV6, IPV6_MTU_DISCOVER, &dont, sizeof(dont)) < 0)
254
    ERR("IPV6_MTU_DISCOVER");
255

  
256
  return 0;
257
}
310 258

  
311 259
int sk_priority_control = 7;
312 260

  
313
static int
261
static inline int
314 262
sk_set_priority(sock *s, int prio)
315 263
{
316 264
  if (setsockopt(s->fd, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)) < 0)
317
  {
318
    log(L_WARN "sk_set_priority: setsockopt: %m");
319
    return -1;
320
  }
265
    ERR("SO_PRIORITY");
321 266

  
322 267
  return 0;
323 268
}
269

  

Also available in: Unified diff