2
2
* packet.c Generic packet manipulation functions.
4
* Version: $Id: packet.c,v 1.21 2008/05/29 15:00:54 aland Exp $
6
6
* This library is free software; you can redistribute it and/or
7
7
* modify it under the terms of the GNU Lesser General Public
175
175
int fr_socket(fr_ipaddr_t *ipaddr, int port)
179
178
struct sockaddr_storage salocal;
182
181
if ((port < 0) || (port > 65535)) {
183
librad_log("Port %d is out of allowed bounds", port);
182
fr_strerror_printf("Port %d is out of allowed bounds", port);
187
186
sockfd = socket(ipaddr->af, SOCK_DGRAM, 0);
188
187
if (sockfd < 0) {
189
librad_log("cannot open socket: %s", strerror(errno));
188
fr_strerror_printf("cannot open socket: %s", strerror(errno));
197
196
if (udpfromto_init(sockfd) != 0) {
199
librad_log("cannot initialize udpfromto: %s", strerror(errno));
198
fr_strerror_printf("cannot initialize udpfromto: %s", strerror(errno));
205
sport = htons(sport);
206
memset(&salocal, 0, sizeof(salocal));
207
if (ipaddr->af == AF_INET) {
208
struct sockaddr_in s4;
210
s4.sin_family = AF_INET;
211
s4.sin_addr = ipaddr->ipaddr.ip4addr;
214
memset(&salocal, 0, sizeof(salocal));
215
memcpy(&salocal, &s4, salen);
204
if (!fr_ipaddr2sockaddr(ipaddr, port, &salocal, &salen)) {
217
208
#ifdef HAVE_STRUCT_SOCKADDR_IN6
218
} else if (ipaddr->af == AF_INET6) {
219
struct sockaddr_in6 s6;
221
s6.sin6_family = AF_INET6;
222
s6.sin6_addr = ipaddr->ipaddr.ip6addr;
223
s6.sin6_port = sport;
225
memset(&salocal, 0, sizeof(salocal));
226
memcpy(&salocal, &s6, salen);
209
if (ipaddr->af == AF_INET6) {
230
211
* Listening on '::' does NOT get you IPv4 to
231
212
* IPv6 mapping. You've got to listen on an IPv4
241
222
(char *)&on, sizeof(on));
243
224
#endif /* IPV6_V6ONLY */
245
226
#endif /* HAVE_STRUCT_SOCKADDR_IN6 */
247
return sockfd; /* don't bind it */
228
if (ipaddr->af == AF_INET) {
231
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
233
* Disable PMTU discovery. On Linux, this
234
* also makes sure that the "don't fragment"
237
flag = IP_PMTUDISC_DONT;
238
setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER,
239
&flag, sizeof(flag));
242
#if defined(IP_DONTFRAG)
244
* Ensure that the "don't fragment" flag is zero.
247
setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG,
248
&flag, sizeof(flag));
250
252
if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
252
librad_log("cannot bind socket: %s", strerror(errno));
254
fr_strerror_printf("cannot bind socket: %s", strerror(errno));
385
if (!fr_sockaddr2ipaddr(&src, sizeof_src, &ps->ipaddr, &ps->port)) {
384
390
* Grab IP addresses & ports from the sockaddr.
386
ps->ipaddr.af = src.ss_family;
387
392
if (src.ss_family == AF_INET) {
388
struct sockaddr_in s4;
390
memcpy(&s4, &src, sizeof(s4));
391
ps->ipaddr.ipaddr.ip4addr = s4.sin_addr;
392
ps->port = ntohs(s4.sin_port);
394
393
if (ps->ipaddr.ipaddr.ip4addr.s_addr == INADDR_ANY) {
395
394
ps->inaddr_any = 1;
398
397
#ifdef HAVE_STRUCT_SOCKADDR_IN6
399
398
} else if (src.ss_family == AF_INET6) {
400
struct sockaddr_in6 s6;
402
memcpy(&s6, &src, sizeof(s6));
403
ps->ipaddr.ipaddr.ip6addr = s6.sin6_addr;
404
ps->port = ntohs(s6.sin6_port);
406
399
if (IN6_IS_ADDR_UNSPECIFIED(&ps->ipaddr.ipaddr.ip6addr)) {
407
400
ps->inaddr_any = 1;
686
680
free_mask = ~((~pd->id[id]) & pl->mask);
683
* This ID has at least one socket free. Check the sockets
684
* to see if they are satisfactory for the caller.
689
687
for (i = 0; i < MAX_SOCKETS; i++) {
690
688
if (pl->sockets[i].sockfd == -1) continue; /* paranoia */
692
if ((free_mask & (1 << i)) == 0) {
698
if (start < 0) return 0; /* bad error */
700
pd->id[id] |= (1 << start);
701
ps = &pl->sockets[start];
691
* This ID is allocated.
693
if ((free_mask & (1 << i)) != 0) continue;
696
* If the caller cares about the source address,
697
* try to re-use that. This means that the
698
* requested source address is set, AND this
699
* socket wasn't bound to "*", AND the requested
700
* source address is the same as this socket
703
if ((request->src_ipaddr.af != AF_UNSPEC) &&
704
!pl->sockets[i].inaddr_any &&
705
(fr_ipaddr_cmp(&request->src_ipaddr, &pl->sockets[i].ipaddr) != 0)) continue;
708
* They asked for a specific address, and this socket
709
* is bound to a wildcard address. Ignore this one, too.
711
if ((request->src_ipaddr.af != AF_UNSPEC) &&
712
pl->sockets[i].inaddr_any) continue;
719
goto redo; /* keep searching IDs */
722
pd->id[id] |= (1 << fd);
723
ps = &pl->sockets[fd];
703
725
ps->num_outgoing++;
704
726
pl->num_outgoing++;