Prior to leasing an IPv4 ping it to check if it is already in use.

This commit is contained in:
Nikos Mavrogiannopoulos
2013-04-27 19:49:36 +03:00
parent b0ff05dee9
commit fed7861b89
9 changed files with 484 additions and 109 deletions

3
NEWS
View File

@@ -1,7 +1,8 @@
* Version 0.1.2 (unreleased)
- Several updates to allow compilation in FreeBSD.
- Prior to leasing an IPv4 ping it to check if it is
already in use.
* Version 0.1.1 (released 2013-04-03)

View File

@@ -716,6 +716,9 @@
/* Define to 1 if you have the `snprintf' function. */
#undef HAVE_SNPRINTF
/* Do we have sockaddr.sa_len? */
#undef HAVE_SOCKADDR_SA_LEN
/* Define to 1 if you have the <stdarg.h> header file. */
#undef HAVE_STDARG_H

View File

@@ -77,6 +77,12 @@ gl_INIT
AC_LIB_HAVE_LINKFLAGS(crypt,, [#include <unistd.h>], [crypt(0,0);])
AC_LIB_HAVE_LINKFLAGS(util,, [#include <utmpx.h>], [pututxline(0);])
AC_LIB_HAVE_LINKFLAGS(wrap,, [#include <tcpd.h>], [hosts_access(0);])
AC_CHECK_MEMBER([struct sockaddr.sa_len],
[AC_DEFINE(HAVE_SOCKADDR_SA_LEN, 1, [Do we have sockaddr.sa_len?])], [],
[
#include <sys/types.h>
#include <sys/socket.h>
])
if [ test -z "$LIBWRAP" ];then
libwrap_enabled="no"

View File

@@ -18,7 +18,7 @@ ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
config.c pam.c pam.h worker-resume.c worker.h main-resume.c main.h \
main-user.c cookies-gdbm.c cookies-hash.c worker-misc.c setproctitle.h \
setproctitle.c worker-privs.c plain.c plain.h common.h common.c \
sec-mod.c sec-mod.h script-list.h die.c die.h \
sec-mod.c sec-mod.h script-list.h die.c die.h icmp-ping.c icmp-ping.h \
$(CCAN_SOURCES)
ocserv_SOURCES += ocserv-args.def ocserv-args.c ocserv-args.h

349
src/icmp-ping.c Normal file
View File

@@ -0,0 +1,349 @@
/* vi: set sw=4 ts=4: */
/*
* Mini ping implementation for busybox
*
* Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
*
* Adapted from the ping in netkit-base 0.10:
* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Muuss.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* from ping6.c:
* Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
*
* This version of ping is adapted from the ping in netkit-base 0.10,
* which is:
*
* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Muuss.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
* ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
*
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This version is an adaptation of ping.c from busybox.
* The code was modified by Bart Visscher <magick@linux-fan.com>
*/
/* Ported to ocserv by Nikos Mavrogiannopoulos */
#include <config.h>
#include <main.h>
#include <net/if.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <gnutls/crypto.h>
#include <icmp-ping.h>
/* I see RENUMBERED constants in bits/in.h - !!?
* What a fuck is going on with libc? Is it a glibc joke? */
#ifdef IPV6_2292HOPLIMIT
#undef IPV6_HOPLIMIT
#define IPV6_HOPLIMIT IPV6_2292HOPLIMIT
#endif
enum {
DEFDATALEN = 56,
MAXIPLEN = 60,
MAXICMPLEN = 76,
MAXPACKET = 65468,
MAX_DUP_CHK = (8 * 128),
MAXWAIT = 10,
PINGINTERVAL = 1, /* 1 second */
};
/* common routines */
static int in_cksum(unsigned short *buf, int sz)
{
int nleft = sz;
int sum = 0;
unsigned short *w = buf;
unsigned short ans = 0;
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
if (nleft == 1) {
*(unsigned char *) (&ans) = *(unsigned char *) w;
sum += ans;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
ans = ~sum;
return ans;
}
inline static int retry(e)
{
if (e == EAGAIN || e == EWOULDBLOCK || e == EINTR)
return 1;
else
return 0;
}
#define PING_TIMEOUT 3
static
ssize_t recvfrom_timeout(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t * addrlen)
{
fd_set rfds;
struct timeval tv;
int ret;
FD_ZERO(&rfds);
FD_SET(sockfd, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 250000;
ret = select(sockfd + 1, &rfds, NULL, NULL, &tv);
if (ret == -1)
return -1;
else if (ret > 0)
return recvfrom(sockfd, buf, len, 0, src_addr, addrlen);
else
return -1;
}
int icmp_ping4(main_server_st * s, struct sockaddr_in *addr1,
struct sockaddr_in *addr2)
{
struct icmp *pkt;
int pingsock, c;
char packet1[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
char packet2[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
char buf1[64], buf2[64];
time_t now;
uint16_t id1, id2;
unsigned gotreply = 0, unreachable = 0;
gnutls_rnd(GNUTLS_RND_NONCE, &id1, sizeof(id1));
gnutls_rnd(GNUTLS_RND_NONCE, &id2, sizeof(id2));
pingsock = socket(AF_INET, SOCK_RAW, 1);
pkt = (struct icmp *) packet1;
memset(pkt, 0, sizeof(packet1));
pkt->icmp_type = ICMP_ECHO;
pkt->icmp_id = id1;
pkt->icmp_cksum =
in_cksum((unsigned short *) pkt, sizeof(packet1));
pkt = (struct icmp *) packet2;
memset(pkt, 0, sizeof(packet2));
pkt->icmp_type = ICMP_ECHO;
pkt->icmp_id = id2;
pkt->icmp_cksum =
in_cksum((unsigned short *) pkt, sizeof(packet2));
while ((c = sendto(pingsock, packet1, DEFDATALEN + ICMP_MINLEN, 0,
(struct sockaddr *) addr1,
sizeof(*addr1)) == -1) && retry(errno));
while ((c =
sendto(pingsock, packet2, DEFDATALEN + ICMP_MINLEN, 0,
(struct sockaddr *) addr2, sizeof(*addr2)) == -1)
&& retry(errno));
/* listen for replies */
now = time(0);
while (time(0) - now < PING_TIMEOUT
&& (unreachable + gotreply) < 2) {
struct sockaddr_in from;
socklen_t fromlen = sizeof(from);
c = recvfrom_timeout(pingsock, packet1, sizeof(packet1), 0,
(struct sockaddr *) &from, &fromlen);
if (c < 0) {
continue;
} else if (c >= 76 && fromlen == sizeof(struct sockaddr_in)) { /* icmp6_hdr */
if (memcmp
(SA_IN_P(&from), SA_IN_P(addr1),
SA_IN_SIZE(sizeof(*addr1))) == 0 ||
memcmp
(SA_IN_P(&from), SA_IN_P(addr2),
SA_IN_SIZE(sizeof(*addr2))) == 0) {
struct iphdr *iphdr =
(struct iphdr *) packet1;
pkt = (struct icmp *) (packet1 + (iphdr->ihl << 2)); /* skip ip hdr */
if (pkt->icmp_type == ICMP_ECHOREPLY)
gotreply++;
else if (pkt->icmp_type ==
ICMP_DEST_UNREACH)
unreachable++;
}
}
}
close(pingsock);
if (gotreply > 0) {
mslog(s, NULL, LOG_INFO,
"pinged %s and %s and are in use",
human_addr((void *) addr1, sizeof(struct sockaddr_in),
buf1, sizeof(buf1)),
human_addr((void *) addr2, sizeof(struct sockaddr_in),
buf2, sizeof(buf2)));
return gotreply;
} else {
mslog(s, NULL, LOG_INFO,
"pinged %s and %s and are not in use",
human_addr((void *) addr1, sizeof(struct sockaddr_in),
buf1, sizeof(buf1)),
human_addr((void *) addr2, sizeof(struct sockaddr_in),
buf2, sizeof(buf2)));
return 0;
}
}
int icmp_ping6(main_server_st * s,
struct sockaddr_in6* addr1, struct sockaddr_in6* addr2)
{
struct icmp6_hdr *pkt;
char buf1[64], buf2[64];
int pingsock, c;
int sockopt;
char packet1[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
char packet2[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
uint16_t id1, id2;
unsigned gotreply = 0, unreachable = 0;
time_t now;
gnutls_rnd(GNUTLS_RND_NONCE, &id1, sizeof(id1));
gnutls_rnd(GNUTLS_RND_NONCE, &id2, sizeof(id2));
pingsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
pkt = (struct icmp6_hdr *) packet1;
memset(pkt, 0, sizeof(packet1));
pkt->icmp6_type = ICMP6_ECHO_REQUEST;
pkt->icmp6_id = id1;
pkt = (struct icmp6_hdr *) packet2;
memset(pkt, 0, sizeof(packet2));
pkt->icmp6_type = ICMP6_ECHO_REQUEST;
pkt->icmp6_id = id1;
sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM,
&sockopt, sizeof(sockopt));
while ((c =
sendto(pingsock, packet1,
DEFDATALEN + sizeof(struct icmp6_hdr), 0,
(struct sockaddr *) addr1,
sizeof(*addr1)) == -1) && retry(errno));
while ((c =
sendto(pingsock, packet2,
DEFDATALEN +
sizeof(struct icmp6_hdr), 0,
(struct sockaddr *) addr2, sizeof(*addr2)) == -1)
&& retry(errno));
/* listen for replies */
now = time(0);
while (time(0) - now < PING_TIMEOUT
&& (unreachable + gotreply) < 2) {
struct sockaddr_in6 from;
socklen_t fromlen = sizeof(from);
c = recvfrom_timeout(pingsock, packet1,
sizeof(packet1), 0, (struct sockaddr *)
&from, &fromlen);
if (c < 0) {
continue;
} else if (c >= 8 && fromlen == sizeof(struct sockaddr_in6)) { /* icmp6_hdr */
if (memcmp
(SA_IN6_P(&from), SA_IN6_P(addr1),
SA_IN_SIZE(sizeof(*addr1))) == 0 ||
memcmp(SA_IN6_P(&from),
SA_IN6_P(addr2),
SA_IN_SIZE(sizeof(*addr2))) == 0) {
pkt = (struct icmp6_hdr *) packet1;
if (pkt->icmp6_type == ICMP6_ECHO_REPLY)
gotreply++;
else if (pkt->icmp6_type ==
ICMP_DEST_UNREACH)
unreachable++;
}
}
}
close(pingsock);
if (gotreply > 0) {
mslog(s, NULL, LOG_INFO,
"pinged %s and %s and are in use",
human_addr((void *) addr1, sizeof(struct sockaddr_in6),
buf1, sizeof(buf1)),
human_addr((void *) addr2, sizeof(struct sockaddr_in6),
buf2, sizeof(buf2)));
return gotreply;
} else {
mslog(s, NULL, LOG_INFO,
"pinged %s and %s and are not in use",
human_addr((void *) addr1, sizeof(struct sockaddr_in6),
buf1, sizeof(buf1)),
human_addr((void *) addr2, sizeof(struct sockaddr_in6),
buf2, sizeof(buf2)));
return 0;
}
}

11
src/icmp-ping.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef ICMP_PING_H
# define ICMP_PING_H
#include <main.h>
/* returns the number of positive replies received or
* 0 if no host with this IP exists. */
int icmp_ping4(main_server_st* s, struct sockaddr_in* addr1, struct sockaddr_in* addr2);
int icmp_ping6(main_server_st* s, struct sockaddr_in6* addr1, struct sockaddr_in6* addr2);
#endif

View File

@@ -42,8 +42,7 @@ const char *human_addr(const struct sockaddr *sa, socklen_t salen,
buf++;
buflen--;
if (getnameinfo(sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) !=
0)
if (getnameinfo(sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) != 0)
return NULL;
l = strlen(buf);
@@ -58,8 +57,7 @@ const char *human_addr(const struct sockaddr *sa, socklen_t salen,
buf++;
buflen--;
if (getnameinfo(sa, salen, NULL, 0, buf, buflen, NI_NUMERICSERV) !=
0)
if (getnameinfo(sa, salen, NULL, 0, buf, buflen, NI_NUMERICSERV) != 0)
return NULL;
return save_buf;

201
src/tun.c
View File

@@ -30,6 +30,7 @@
#include <stdlib.h>
#include <errno.h>
#include <cloexec.h>
#include <icmp-ping.h>
#ifdef __linux__
# include <linux/if_tun.h>
@@ -44,34 +45,43 @@
#include <main.h>
#include <ccan/list/list.h>
static int bignum_add1 (uint8_t * num, unsigned size)
/* INCREMENT taken from nettle's macros */
/* Requires that size > 0 */
#define INCREMENT(size, ctr) \
do { \
unsigned increment_i = (size) - 1; \
if (++(ctr)[increment_i] == 0) \
while (increment_i > 0 \
&& ++(ctr)[--increment_i] == 0 ) \
; \
} while (0)
static void bignum_add (uint8_t * num, unsigned size, unsigned step)
{
register int i, y = 0;
register int i;
register unsigned tmp, y;
for (i = size-1; i >= 0; i--)
{
y = 0;
if (num[i] == 0xff)
{
num[i] = 0;
y = 1;
}
tmp = num[i];
num[i] += step;
if (num[i] < tmp)
y = 1;
else
num[i]++;
y = 0;
if (y == 0)
break;
}
return 0;
}
static int get_avail_network_addresses(const struct cfg_st *config, const struct lease_st *last4,
static int get_avail_network_addresses(main_server_st* s, const struct lease_st *last4,
const struct lease_st *last6, struct lease_st* lease)
{
struct sockaddr_storage tmp, mask, network;
unsigned i;
int ret;
int ret, step;
lease->rip4_len = 0;
lease->lip4_len = 0;
@@ -80,138 +90,116 @@ static int get_avail_network_addresses(const struct cfg_st *config, const struct
memset(&tmp, 0, sizeof(tmp));
if (config->network.ipv4 && config->network.ipv4_netmask) {
if (s->config->network.ipv4 && s->config->network.ipv4_netmask) {
ret =
inet_pton(AF_INET, config->network.ipv4, SA_IN_P(&network));
inet_pton(AF_INET, s->config->network.ipv4, SA_IN_P(&network));
if (ret != 1) {
syslog(LOG_ERR, "Error reading IP: %s\n", config->network.ipv4);
mslog(s, NULL, LOG_ERR, "Error reading IP: %s\n", s->config->network.ipv4);
return -1;
}
ret =
inet_pton(AF_INET, config->network.ipv4_netmask, SA_IN_P(&mask));
inet_pton(AF_INET, s->config->network.ipv4_netmask, SA_IN_P(&mask));
if (ret != 1) {
syslog(LOG_ERR, "Error reading mask: %s\n", config->network.ipv4_netmask);
mslog(s, NULL, LOG_ERR, "Error reading mask: %s\n", s->config->network.ipv4_netmask);
return -1;
}
/* mask the network (just in case it is wrong) */
for (i=0;i<sizeof(struct in_addr);i++)
SA_IN_U8_P(&network)[i] &= (SA_IN_U8_P(&mask)[i]);
((struct sockaddr_in*)&network)->sin_family = AF_INET;
memcpy(&tmp, &network, sizeof(tmp));
((struct sockaddr_in*)&tmp)->sin_family = AF_INET;
((struct sockaddr_in*)&network)->sin_family = AF_INET;
}
if (last4 != NULL) {
memcpy(&tmp, &last4->rip4, last4->rip4_len);
} else {
memcpy(&tmp, &network, sizeof(tmp));
((struct sockaddr_in*)&tmp)->sin_family = AF_INET;
}
/* read the network */
if (last4 == NULL && (config->network.ipv4 && config->network.ipv4_netmask)) {
/* add one to get local IP */
i = sizeof(struct in_addr)-1;
SA_IN_U8_P(&tmp)[i]++;
lease->lip4_len = sizeof(struct sockaddr_in);
memcpy(&lease->lip4, &tmp, lease->lip4_len);
/* add one to get remote IP */
i = sizeof(struct in_addr)-1;
SA_IN_U8_P(&tmp)[i]++;
lease->rip4_len = sizeof(struct sockaddr_in);
memcpy(&lease->rip4, &tmp, lease->rip4_len);
} else if (last4 != NULL) {
lease->lip4_len = last4->rip4_len;
memcpy(&lease->lip4, &last4->rip4, last4->rip4_len);
bignum_add1(SA_IN_U8_P(&lease->lip4), sizeof(struct in_addr));
if (SA_IN_U8_P(&lease->lip4)[3] == 255) /* broadcast */
bignum_add1(SA_IN_U8_P(&lease->lip4), sizeof(struct in_addr));
lease->rip4_len = last4->rip4_len;
memcpy(&lease->rip4, &lease->lip4, lease->rip4_len);
bignum_add1(SA_IN_U8_P(&lease->rip4), sizeof(struct in_addr));
/* mask the last IP with the netmask */
memcpy(&tmp, &lease->rip4, lease->rip4_len);
for (i=0;i<sizeof(struct in_addr);i++)
SA_IN_U8_P(&tmp)[i] &= (SA_IN_U8_P(&mask)[i]);
memcpy(&lease->lip4, &tmp, sizeof(struct sockaddr_in));
/* the result should match the network */
if (memcmp(SA_IN_U8_P(&network), SA_IN_U8_P(&tmp), sizeof(struct in_addr)) != 0) {
syslog(LOG_ERR, "Reached limit of maximum (v4) IPs.\n");
return -1;
}
step = 1;
do {
bignum_add(SA_IN_U8_P(&lease->lip4), sizeof(struct in_addr), step);
if (SA_IN_U8_P(&lease->lip4)[3] == 255) /* broadcast */
bignum_add(SA_IN_U8_P(&lease->lip4), sizeof(struct in_addr), step);
lease->rip4_len = sizeof(struct sockaddr_in);
memcpy(&lease->rip4, &lease->lip4, sizeof(struct sockaddr_in));
bignum_add(SA_IN_U8_P(&lease->rip4), sizeof(struct in_addr), step);
/* mask the last IP with the netmask */
memcpy(&tmp, &lease->rip4, lease->rip4_len);
for (i=0;i<sizeof(struct in_addr);i++)
SA_IN_U8_P(&tmp)[i] &= (SA_IN_U8_P(&mask)[i]);
/* the result should match the network */
if (memcmp(SA_IN_U8_P(&network), SA_IN_U8_P(&tmp), sizeof(struct in_addr)) != 0) {
mslog(s, NULL, LOG_ERR, "Reached limit of maximum (v4) IPs.\n");
return -1;
}
} while((step=icmp_ping4(s, (void*)&lease->lip4, (void*)&lease->rip4)) != 0);
}
if (config->network.ipv6 && config->network.ipv6_netmask) {
if (s->config->network.ipv6 && s->config->network.ipv6_netmask) {
ret =
inet_pton(AF_INET6, config->network.ipv6, SA_IN6_P(&network));
inet_pton(AF_INET6, s->config->network.ipv6, SA_IN6_P(&network));
if (ret != 1) {
syslog(LOG_ERR, "Error reading IP: %s\n", config->network.ipv6);
mslog(s, NULL, LOG_ERR, "Error reading IP: %s\n", s->config->network.ipv6);
return -1;
}
ret =
inet_pton(AF_INET6, config->network.ipv6_netmask, SA_IN6_P(&mask));
inet_pton(AF_INET6, s->config->network.ipv6_netmask, SA_IN6_P(&mask));
if (ret != 1) {
syslog(LOG_ERR, "Error reading mask: %s\n", config->network.ipv6_netmask);
mslog(s, NULL, LOG_ERR, "Error reading mask: %s\n", s->config->network.ipv6_netmask);
return -1;
}
/* mask the network */
for (i=0;i<sizeof(struct in6_addr);i++)
SA_IN6_U8_P(&network)[i] &= (SA_IN6_U8_P(&mask)[i]);
memcpy(&tmp, &network, sizeof(tmp));
((struct sockaddr_in6*)&tmp)->sin6_family = AF_INET6;
((struct sockaddr_in6*)&network)->sin6_family = AF_INET6;
}
if (last6 == NULL && (config->network.ipv6 && config->network.ipv6_netmask)) {
/* add one to get local IP */
i = sizeof(struct in6_addr)-1;
SA_IN6_U8_P(&tmp)[i]++;
if (last6 != NULL) {
memcpy(&tmp, &last6->rip6, last6->rip6_len);
} else {
memcpy(&tmp, &network, sizeof(tmp));
((struct sockaddr_in6*)&tmp)->sin6_family = AF_INET6;
}
lease->lip6_len = sizeof(struct sockaddr_in6);
memcpy(&lease->lip6, &tmp, lease->lip6_len);
memcpy(&lease->lip6, &tmp, sizeof(struct sockaddr_in6));
/* add one to get remote IP */
i = sizeof(struct in6_addr)-1;
SA_IN6_U8_P(&tmp)[i]++;
lease->rip6_len = sizeof(struct sockaddr_in6);
memcpy(&lease->rip6, &tmp, lease->rip6_len);
} else if (last6 != NULL) {
step = 1;
do {
bignum_add(SA_IN6_U8_P(&lease->lip6), sizeof(struct in6_addr), step);
lease->lip6_len = last6->rip6_len;
memcpy(&lease->lip6, &last6->rip6, last6->rip6_len);
bignum_add1(SA_IN6_U8_P(&lease->lip6), sizeof(struct in6_addr));
lease->rip6_len = last6->rip6_len;
memcpy(&lease->rip6, &lease->lip6, lease->rip6_len);
bignum_add(SA_IN6_U8_P(&lease->rip6), sizeof(struct in6_addr), step);
lease->rip6_len = last6->rip6_len;
memcpy(&lease->rip6, &lease->lip6, lease->rip6_len);
bignum_add1(SA_IN6_U8_P(&lease->rip6), sizeof(struct in6_addr));
/* mask the last IP with the netmask */
memcpy(&tmp, &lease->rip6, lease->rip6_len);
for (i=0;i<sizeof(struct in6_addr);i++)
SA_IN6_U8_P(&tmp)[i] &= (SA_IN6_U8_P(&mask)[i]);
/* mask the last IP with the netmask */
memcpy(&tmp, &lease->rip6, lease->rip6_len);
for (i=0;i<sizeof(struct in6_addr);i++)
SA_IN6_U8_P(&tmp)[i] &= (SA_IN6_U8_P(&mask)[i]);
/* the result should match the network */
if (memcmp(SA_IN6_U8_P(&network), SA_IN6_U8_P(&tmp), sizeof(struct in6_addr)) != 0) {
syslog(LOG_ERR, "Reached limit of maximum (v6) IPs.\n");
return -1;
}
/* the result should match the network */
if (memcmp(SA_IN6_U8_P(&network), SA_IN6_U8_P(&tmp), sizeof(struct in6_addr)) != 0) {
mslog(s, NULL, LOG_ERR, "Reached limit of maximum (v6) IPs.\n");
return -1;
}
} while((step=icmp_ping6(s, (void*)&lease->lip6, (void*)&lease->rip6)) != 0);
}
if (lease->lip6_len == 0 && lease->lip4_len == 0) {
syslog(LOG_ERR, "No IPv4 or IPv6 addresses are configured. Cannot obtain lease.\n");
mslog(s, NULL, LOG_ERR, "No IPv4 or IPv6 addresses are configured. Cannot obtain lease.\n");
return -1;
}
@@ -315,10 +303,15 @@ int open_tun(main_server_st* s, struct lease_st** l)
/* try to re-use an address */
list_for_each(&s->tun->head, tmp, list) {
/* if the device isn't in use by the server and the IPs
* are free. */
if (tmp->in_use == 0) {
lease = tmp;
mslog(s, NULL, LOG_INFO, "reusing tun device %s\n", lease->name);
break;
if ((tmp->lip6_len != 0 && icmp_ping6(s, (void*)&tmp->lip6, (void*)&tmp->rip6) == 0) ||
(tmp->lip4_len != 0 && icmp_ping4(s, (void*)&tmp->lip4, (void*)&tmp->rip4) == 0)) {
lease = tmp;
mslog(s, NULL, LOG_INFO, "reusing tun device %s\n", lease->name);
break;
}
}
}
@@ -339,7 +332,7 @@ int open_tun(main_server_st* s, struct lease_st** l)
break;
}
ret = get_avail_network_addresses(s->config, last4, last6, lease);
ret = get_avail_network_addresses(s, last4, last6, lease);
if (ret < 0) {
free(lease);
return -1;
@@ -353,6 +346,8 @@ int open_tun(main_server_st* s, struct lease_st** l)
/* No need to free the lease after this point.
*/
/* Obtain a free tun device */
#ifdef __linux__
tunfd = open("/dev/net/tun", O_RDWR);
if (tunfd < 0) {

View File

@@ -13,6 +13,18 @@
#include <netinet/in.h>
#include <minmax.h>
#ifdef __GNUC__
# define _OCSERV_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
# if _OCSERV_GCC_VERSION >= 30000
# define _ATTR_PACKED __attribute__ ((__packed__))
# endif
#endif /* __GNUC__ */
#ifndef _ATTR_PACKED
# define _ATTR_PACKED
#endif
#define AC_PKT_DATA 0 /* Uncompressed data */
#define AC_PKT_DPD_OUT 3 /* Dead Peer Detection */
#define AC_PKT_DPD_RESP 4 /* DPD response */