mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 00:37:00 +08:00
Prior to leasing an IPv4 ping it to check if it is already in use.
This commit is contained in:
3
NEWS
3
NEWS
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
349
src/icmp-ping.c
Normal 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
11
src/icmp-ping.h
Normal 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
|
||||
@@ -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
201
src/tun.c
@@ -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) {
|
||||
|
||||
12
src/vpn.h
12
src/vpn.h
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user