Update and fix x2ltpd, add connect script

Remove unwanted services from default configuration
Ship xl2tpd-config
Use kernel mode L2TP
Don't scribble on ipparam

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>

git-svn-id: svn://svn.openwrt.org/openwrt/packages@31561 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
juhosg 2012-05-02 19:28:10 +00:00
parent e9e068ebf9
commit cd031d81e6
5 changed files with 598 additions and 20 deletions

View File

@ -8,12 +8,14 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=xl2tpd
PKG_VERSION:=1.3.0
PKG_VERSION:=1.3.1
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=ftp://ftp.xelerance.com/xl2tpd/
PKG_MD5SUM:=28264284552c442b24cf421755a2bb48
# Host seems to be down.
#PKG_SOURCE_URL:=ftp://ftp.xelerance.com/xl2tpd/
PKG_MD5SUM:=cf61576fef5c2d6c68279a408ec1f0d5
PKG_SOURCE_URL:=http://pkgs.fedoraproject.org/lookaside/pkgs/xl2tpd/xl2tpd-$(PKG_VERSION).tar.gz/$(PKG_MD5SUM)/
PKG_INSTALL:=1
@ -25,6 +27,7 @@ define Package/xl2tpd
TITLE:=An L2TP (Layer 2 Tunneling Protocol) daemon
URL:=http://www.xelerance.com/software/xl2tpd/
SUBMENU:=VPN
DEPENDS:=+ppp-mod-pppol2tp +ip +resolveip
endef
define Package/xl2tpd/description
@ -46,6 +49,7 @@ endef
define Package/xl2tpd/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/local/sbin/xl2tpd $(1)/usr/sbin/
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/local/sbin/xl2tpd-control $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/xl2tpd.init $(1)/etc/init.d/xl2tpd
@ -56,6 +60,9 @@ define Package/xl2tpd/install
$(INSTALL_DIR) $(1)/etc/ppp
$(INSTALL_DATA) ./files/options.xl2tpd $(1)/etc/ppp/
$(INSTALL_DIR) $(1)/lib/network
$(INSTALL_DATA) ./files/l2tp.sh $(1)/lib/network
endef
$(eval $(call BuildPackage,xl2tpd))

124
net/xl2tpd/files/l2tp.sh Normal file
View File

@ -0,0 +1,124 @@
find_route() {
ip route get $1 | sed -e 's/ /\n/g' | \
sed -ne '1p;/via/{N;p};/dev/{N;p};/src/{N;p};/mtu/{N;p}'
}
scan_l2tp() {
config_set "$1" device "l2tp-$1"
}
stop_interface_l2tp() {
local config="$1"
local lock="/var/lock/l2tp-${config}"
local optfile="/tmp/l2tp/options.${config}"
local l2tpcontrol=/var/run/xl2tpd/l2tp-control
lock "$lock"
[ -p ${l2tpcontrol} ] && echo "r l2tp-${config}" > ${l2tpcontrol}
rm -f ${optfile}
for ip in $(uci_get_state network "$1" serv_addrs); do
ip route del "$ip" 2>/dev/null
done
lock -u "$lock"
}
setup_interface_l2tp() {
local config="$2"
local lock="/var/lock/l2tp-${config}"
local optfile="/tmp/l2tp/options.${config}"
lock "$lock"
if [ ! -p /var/run/xl2tpd/l2tp-control ]; then
/etc/init.d/xl2tpd start
fi
local device
config_get device "$config" device "l2tp-$config"
local server
config_get server "$config" server
local username
config_get username "$config" username
local password
config_get password "$config" password
local keepalive
config_get keepalive "$config" keepalive
local pppd_options
config_get pppd_options "$config" pppd_options
local defaultroute
config_get_bool defaultroute "$config" defaultroute 1
[ "$defaultroute" -eq 1 ] && \
defaultroute="defaultroute replacedefaultroute" || defaultroute="nodefaultroute"
local interval="${keepalive##*[, ]}"
[ "$interval" != "$keepalive" ] || interval=5
local dns
config_get dns "$config" dns
local has_dns=0
local peer_default=1
[ -n "$dns" ] && {
has_dns=1
peer_default=0
}
local peerdns
config_get_bool peerdns "$config" peerdns $peer_default
[ "$peerdns" -eq 1 ] && {
peerdns="usepeerdns"
} || {
peerdns=""
add_dns "$config" $dns
}
local ipv6
config_get ipv6 "$config" ipv6 1
[ "$ipv6" -eq 1 ] && ipv6="+ipv6" || ipv6=""
local serv_addrs=""
for ip in $(resolveip -t 3 "$server"); do
append serv_addrs "$ip"
ip route replace $(find_route $ip)
done
uci_toggle_state network "$config" serv_addrs "$serv_addrs"
# fix up the netmask
config_get netmask "$config" netmask
[ -z "$netmask" -o -z "$device" ] || ifconfig $device netmask $netmask
config_get mtu "$config" mtu
mkdir -p /tmp/l2tp
echo ${keepalive:+lcp-echo-interval $interval lcp-echo-failure ${keepalive%%[, ]*}} > "${optfile}"
echo "$peerdns" >> "${optfile}"
echo "$defaultroute" >> "${optfile}"
echo "${username:+user \"$username\" password \"$password\"}" >> "${optfile}"
echo "ipparam \"$config\"" >> "${optfile}"
echo "ifname \"l2tp-$config\"" >> "${optfile}"
# Don't wait for LCP term responses; exit immediately when killed.
echo "lcp-max-terminate 0" >> "${optfile}"
echo "${ipv6} ${pppd_options}" >> "${optfile}"
xl2tpd-control remove l2tp-${config}
# Wait and ensure pppd has died.
while [ -d /sys/class/net/l2tp-${config} ]; do
sleep 1
done
xl2tpd-control add l2tp-${config} pppoptfile=${optfile} lns=${server} redial=yes redial timeout=20
xl2tpd-control connect l2tp-${config}
lock -u "${lock}"
}

View File

@ -3,21 +3,21 @@ port = 1701
auth file = /etc/xl2tpd/xl2tp-secrets
access control = no
[lns default]
exclusive = yes
ip range = 192.168.254.202-192.168.254.210
lac = 10.0.1.2
hidden bit = no
local ip = 192.168.254.200
length bit = yes
refuse authentication = yes
name = VersaLink
ppp debug = yes
pppoptfile = /etc/ppp/options.xl2tpd
;[lns default]
;exclusive = yes
;ip range = 192.168.254.202-192.168.254.210
;lac = 10.0.1.2
;hidden bit = no
;local ip = 192.168.254.200
;length bit = yes
;refuse authentication = yes
;name = VersaLink
;ppp debug = yes
;pppoptfile = /etc/ppp/options.xl2tpd
[lac left]
lns = 10.0.1.2
refuse authentication = yes
name = VersaLink
ppp debug = yes
pppoptfile = /etc/ppp/options.xl2tpd
;[lac left]
;lns = 10.0.1.2
;refuse authentication = yes
;name = VersaLink
;ppp debug = yes
;pppoptfile = /etc/ppp/options.xl2tpd

View File

@ -0,0 +1,436 @@
diff --git a/Makefile b/Makefile
index 6f6481f..778f38d 100644
--- a/Makefile
+++ b/Makefile
@@ -62,8 +62,8 @@
# are packages seperately (eg kernel-headers on Fedora)
# Note: 2.6.23+ support still needs some changes in the xl2tpd source
#
-#OSFLAGS+= -DUSE_KERNEL
-#
+# Kernel mode fixed by sigwall <fionov@gmail.com>
+OSFLAGS+= -DUSE_KERNEL
#
# Uncomment the next line for FreeBSD
#
diff --git a/call.c b/call.c
index d1b1858..b672f91 100644
--- a/call.c
+++ b/call.c
@@ -680,6 +680,8 @@ struct call *get_call (int tunnel, int call, struct in_addr addr, int port,
st->peer.sin_port = port;
st->refme = refme;
st->refhim = refhim;
+ st->udp_fd = -1;
+ st->pppox_fd = -1;
bcopy (&addr, &st->peer.sin_addr, sizeof (addr));
st->next = tunnels.head;
tunnels.head = st;
diff --git a/control.c b/control.c
index 0892df9..9362ffd 100644
--- a/control.c
+++ b/control.c
@@ -596,6 +596,9 @@ int control_finish (struct tunnel *t, struct call *c)
if (gconfig.debug_state)
l2tp_log (LOG_DEBUG, "%s: sending SCCCN\n", __FUNCTION__);
control_xmit (buf);
+
+ connect_pppol2tp(t);
+
/* Schedule a HELLO */
tv.tv_sec = HELLO_DELAY;
tv.tv_usec = 0;
@@ -608,6 +611,7 @@ int control_finish (struct tunnel *t, struct call *c)
"Connection established to %s, %d. Local: %d, Remote: %d (ref=%u/%u).\n",
IPADDY (t->peer.sin_addr),
ntohs (t->peer.sin_port), t->ourtid, t->tid, t->refme, t->refhim);
+
if (t->lac)
{
/* This is part of a LAC, so we want to go ahead
@@ -635,6 +639,9 @@ int control_finish (struct tunnel *t, struct call *c)
IPADDY (t->peer.sin_addr),
ntohs (t->peer.sin_port), t->ourtid, t->tid, t->refme, t->refhim,
t->lns->entname);
+
+ connect_pppol2tp(t);
+
/* Schedule a HELLO */
tv.tv_sec = HELLO_DELAY;
tv.tv_usec = 0;
diff --git a/l2tp.h b/l2tp.h
index 2724fff..856423f 100644
--- a/l2tp.h
+++ b/l2tp.h
@@ -167,6 +167,8 @@ struct tunnel
int ourrws; /* Receive Window Size */
int rxspeed; /* Receive bps */
int txspeed; /* Transmit bps */
+ int udp_fd; /* UDP fd */
+ int pppox_fd; /* PPPOX tunnel fd */
struct call *self;
struct lns *lns; /* LNS that owns us */
struct lac *lac; /* LAC that owns us */
@@ -220,6 +222,7 @@ extern void control_xmit (void *);
extern int ppd;
extern int switch_io; /* jz */
extern int control_fd;
+extern int connect_pppol2tp(struct tunnel *t);
extern int start_pppd (struct call *c, struct ppp_opts *);
extern void magic_lac_dial (void *);
extern int get_entropy (unsigned char *, int);
diff --git a/linux/include/linux/if_pppol2tp.h b/linux/include/linux/if_pppol2tp.h
index a7d6a22..0795e4a 100644
--- a/linux/include/linux/if_pppol2tp.h
+++ b/linux/include/linux/if_pppol2tp.h
@@ -36,6 +36,20 @@ struct pppol2tp_addr
__u16 d_tunnel, d_session; /* For sending outgoing packets */
};
+/* The L2TPv3 protocol changes tunnel and session ids from 16 to 32
+ * bits. So we need a different sockaddr structure.
+ */
+struct pppol2tpv3_addr {
+ pid_t pid; /* pid that owns the fd.
+ * 0 => current */
+ int fd; /* FD of UDP or IP socket to use */
+
+ struct sockaddr_in addr; /* IP address and port to send to */
+
+ __u32 s_tunnel, s_session; /* For matching incoming packets */
+ __u32 d_tunnel, d_session; /* For sending outgoing packets */
+};
+
/* Socket options:
* DEBUG - bitmask of debug message categories
* SENDSEQ - 0 => don't send packets with sequence numbers
diff --git a/network.c b/network.c
index 241bd82..fde250e 100644
--- a/network.c
+++ b/network.c
@@ -22,6 +22,7 @@
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>
+#include <sys/wait.h>
#ifndef LINUX
# include <sys/uio.h>
#endif
@@ -36,6 +37,51 @@ int server_socket; /* Server socket */
int kernel_support; /* Kernel Support there or not? */
#endif
+#ifdef USE_KERNEL
+void modprobe() {
+ char * modules[] = { "l2tp_ppp", "pppol2tp", NULL };
+ char ** module;
+ char buf[256], *tok;
+ int pid, exit_status, fd;
+
+ FILE * fmod = fopen("/proc/modules", "r");
+
+ if (fmod == NULL)
+ return;
+
+ while (fgets(buf, 255, fmod) != NULL) {
+ if ((tok = strtok(buf, " ")) != NULL) {
+ for (module = modules; *module != NULL; ++module) {
+ if (!strcmp(*module, tok)) {
+ fclose(fmod);
+ return;
+ }
+ }
+ }
+ }
+
+ fclose(fmod);
+
+ for (module = modules; *module != NULL; ++module) {
+ if ((pid = fork()) >= 0) {
+ if (pid == 0) {
+ setenv("PATH", "/sbin:/usr/sbin:/bin:/usr/bin", 1);
+ if ((fd = open("/dev/null", O_RDWR)) > -1) {
+ dup2(fd, 1);
+ dup2(fd, 2);
+ }
+ execlp("modprobe", "modprobe", "-q", *module, (char *)NULL);
+ exit(1);
+ } else {
+ if ((pid = waitpid(pid, &exit_status, 0)) != -1 && WIFEXITED(exit_status)) {
+ if (WEXITSTATUS(exit_status) == 0)
+ return;
+ }
+ }
+ }
+ }
+}
+#endif
int init_network (void)
{
@@ -45,6 +91,7 @@ int init_network (void)
server.sin_family = AF_INET;
server.sin_addr.s_addr = gconfig.listenaddr;
server.sin_port = htons (gconfig.port);
+ int flags;
if ((server_socket = socket (PF_INET, SOCK_DGRAM, 0)) < 0)
{
l2tp_log (LOG_CRIT, "%s: Unable to allocate socket. Terminating.\n",
@@ -52,6 +99,10 @@ int init_network (void)
return -EINVAL;
};
+ flags = 1;
+ setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags));
+ setsockopt(server_socket, SOL_SOCKET, SO_NO_CHECK, &flags, sizeof(flags));
+
if (bind (server_socket, (struct sockaddr *) &server, sizeof (server)))
{
close (server_socket);
@@ -91,6 +142,7 @@ int init_network (void)
}
else
{
+ modprobe();
int kernel_fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP);
if (kernel_fd < 0)
{
@@ -321,6 +373,11 @@ int build_fdset (fd_set *readfds)
while (tun)
{
+ if (tun->udp_fd > -1) {
+ if (tun->udp_fd > max)
+ max = tun->udp_fd;
+ FD_SET (tun->udp_fd, readfds);
+ }
call = tun->call_head;
while (call)
{
@@ -390,6 +447,8 @@ void network_thread ()
struct iovec iov;
char cbuf[256];
unsigned int refme, refhim;
+ int * currentfd;
+ int server_socket_processed;
/* This one buffer can be recycled for everything except control packets */
buf = new_buf (MAX_RECV_SIZE);
@@ -428,7 +487,21 @@ void network_thread ()
{
do_control ();
}
- if (FD_ISSET (server_socket, &readfds))
+ server_socket_processed = 0;
+ currentfd = NULL;
+ st = tunnels.head;
+ while (st || !server_socket_processed) {
+ if (st && (st->udp_fd == -1)) {
+ st=st->next;
+ continue;
+ }
+ if (st) {
+ currentfd = &st->udp_fd;
+ } else {
+ currentfd = &server_socket;
+ server_socket_processed = 1;
+ }
+ if (FD_ISSET (*currentfd, &readfds))
{
/*
* Okay, now we're ready for reading and processing new data.
@@ -457,12 +530,19 @@ void network_thread ()
msgh.msg_flags = 0;
/* Receive one packet. */
- recvsize = recvmsg(server_socket, &msgh, 0);
+ recvsize = recvmsg(*currentfd, &msgh, 0);
if (recvsize < MIN_PAYLOAD_HDR_LEN)
{
if (recvsize < 0)
{
+ if (errno == ECONNREFUSED) {
+ close(*currentfd);
+ }
+ if ((errno == ECONNREFUSED) ||
+ (errno == EBADF)) {
+ *currentfd = -1;
+ }
if (errno != EAGAIN)
l2tp_log (LOG_WARNING,
"%s: recvfrom returned error %d (%s)\n",
@@ -567,6 +647,8 @@ void network_thread ()
}
};
}
+ if (st) st=st->next;
+ }
/*
* finished obvious sources, look for data from PPP connections.
@@ -639,3 +721,82 @@ void network_thread ()
}
}
+
+int connect_pppol2tp(struct tunnel *t) {
+#ifdef USE_KERNEL
+ if (kernel_support) {
+ int ufd = -1, fd2 = -1;
+ int flags;
+ struct sockaddr_pppol2tp sax;
+
+ struct sockaddr_in server;
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = gconfig.listenaddr;
+ server.sin_port = htons (gconfig.port);
+ if ((ufd = socket (PF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ l2tp_log (LOG_CRIT, "%s: Unable to allocate UDP socket. Terminating.\n",
+ __FUNCTION__);
+ return -EINVAL;
+ };
+
+ flags=1;
+ setsockopt(ufd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags));
+ setsockopt(ufd, SOL_SOCKET, SO_NO_CHECK, &flags, sizeof(flags));
+
+ if (bind (ufd, (struct sockaddr *) &server, sizeof (server)))
+ {
+ close (ufd);
+ l2tp_log (LOG_CRIT, "%s: Unable to bind UDP socket: %s. Terminating.\n",
+ __FUNCTION__, strerror(errno), errno);
+ return -EINVAL;
+ };
+ server = t->peer;
+ flags = fcntl(ufd, F_GETFL);
+ if (flags == -1 || fcntl(ufd, F_SETFL, flags | O_NONBLOCK) == -1) {
+ l2tp_log (LOG_WARNING, "%s: Unable to set UDP socket nonblock.\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+ if (connect (ufd, (struct sockaddr *) &server, sizeof(server)) < 0) {
+ l2tp_log (LOG_CRIT, "%s: Unable to connect UDP peer. Terminating.\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+
+ t->udp_fd=ufd;
+
+ fd2 = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP);
+ if (fd2 < 0) {
+ l2tp_log (LOG_WARNING, "%s: Unable to allocate PPPoL2TP socket.\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+ flags = fcntl(fd2, F_GETFL);
+ if (flags == -1 || fcntl(fd2, F_SETFL, flags | O_NONBLOCK) == -1) {
+ l2tp_log (LOG_WARNING, "%s: Unable to set PPPoL2TP socket nonblock.\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+ sax.sa_family = AF_PPPOX;
+ sax.sa_protocol = PX_PROTO_OL2TP;
+ sax.pppol2tp.pid = 0;
+ sax.pppol2tp.fd = t->udp_fd;
+ sax.pppol2tp.addr.sin_addr.s_addr = t->peer.sin_addr.s_addr;
+ sax.pppol2tp.addr.sin_port = t->peer.sin_port;
+ sax.pppol2tp.addr.sin_family = AF_INET;
+ sax.pppol2tp.s_tunnel = t->ourtid;
+ sax.pppol2tp.s_session = 0;
+ sax.pppol2tp.d_tunnel = t->tid;
+ sax.pppol2tp.d_session = 0;
+ if ((connect(fd2, (struct sockaddr *)&sax, sizeof(sax))) < 0) {
+ l2tp_log (LOG_WARNING, "%s: Unable to connect PPPoL2TP socket. %d %s\n",
+ __FUNCTION__, errno, strerror(errno));
+ close(fd2);
+ return -EINVAL;
+ }
+ t->pppox_fd = fd2;
+ }
+#endif
+ return 0;
+}
diff --git a/xl2tpd.c b/xl2tpd.c
index 307ac2e..3fb6dd7 100644
--- a/xl2tpd.c
+++ b/xl2tpd.c
@@ -278,7 +278,11 @@ void death_handler (int signal)
struct tunnel *st, *st2;
int sec;
l2tp_log (LOG_CRIT, "%s: Fatal signal %d received\n", __FUNCTION__, signal);
+#ifdef USE_KERNEL
+ if (kernel_support || signal != SIGTERM) {
+#else
if (signal != SIGTERM) {
+#endif
st = tunnels.head;
while (st)
{
@@ -349,7 +353,7 @@ int start_pppd (struct call *c, struct ppp_opts *opts)
int flags;
#endif
int pos = 1;
- int fd2;
+ int fd2 = -1;
#ifdef DEBUG_PPPD
int x;
#endif
@@ -397,7 +401,7 @@ int start_pppd (struct call *c, struct ppp_opts *opts)
sax.sa_family = AF_PPPOX;
sax.sa_protocol = PX_PROTO_OL2TP;
sax.pppol2tp.pid = 0;
- sax.pppol2tp.fd = server_socket;
+ sax.pppol2tp.fd = c->container->udp_fd;
sax.pppol2tp.addr.sin_addr.s_addr = c->container->peer.sin_addr.s_addr;
sax.pppol2tp.addr.sin_port = c->container->peer.sin_port;
sax.pppol2tp.addr.sin_family = AF_INET;
@@ -408,6 +412,7 @@ int start_pppd (struct call *c, struct ppp_opts *opts)
if (connect(fd2, (struct sockaddr *)&sax, sizeof(sax)) < 0) {
l2tp_log (LOG_WARNING, "%s: Unable to connect PPPoL2TP socket.\n",
__FUNCTION__);
+ close(fd2);
return -EINVAL;
}
stropt[pos++] = strdup ("plugin");
@@ -484,7 +489,7 @@ int start_pppd (struct call *c, struct ppp_opts *opts)
dup2 (fd2, 0);
dup2 (fd2, 1);
close(fd2);
-
+ }
/* close all the calls pty fds */
st = tunnels.head;
while (st)
@@ -492,12 +497,17 @@ int start_pppd (struct call *c, struct ppp_opts *opts)
sc = st->call_head;
while (sc)
{
- close (sc->fd);
+#ifdef USE_KERNEL
+ if (kernel_support) {
+ close(st->udp_fd); /* tunnel UDP fd */
+ close(st->pppox_fd); /* tunnel PPPoX fd */
+ } else
+#endif
+ close (sc->fd); /* call pty fd */
sc = sc->next;
}
st = st->next;
}
- }
/* close the UDP socket fd */
close (server_socket);
@@ -615,6 +625,10 @@ void destroy_tunnel (struct tunnel *t)
the memory pointed to by t->chal_us.vector at some other place */
if (t->chal_them.vector)
free (t->chal_them.vector);
+ if (t->pppox_fd > -1 )
+ close (t->pppox_fd);
+ if (t->udp_fd > -1 )
+ close (t->udp_fd);
free (t);
free (me);
}

View File

@ -0,0 +1,11 @@
--- xl2tpd-1.3.1/control.c.orig 2012-04-25 12:59:28.718825985 +0100
+++ xl2tpd-1.3.1/control.c 2012-04-25 12:59:37.063916785 +0100
@@ -905,8 +905,6 @@ int control_finish (struct tunnel *t, st
po = add_opt (po, c->lac->pppoptfile);
}
};
- po = add_opt (po, "ipparam");
- po = add_opt (po, IPADDY (t->peer.sin_addr));
start_pppd (c, po);
opt_destroy (po);
if (c->lac)