summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKozlov Dmitry <xeb@mail.ru>2013-08-28 17:42:10 +0400
committerKozlov Dmitry <xeb@mail.ru>2013-08-28 17:44:29 +0400
commit0614a5ed9e54982604f4c1b4a44617625312e5fd (patch)
treebcccfb25e5e42f49b83387f6e3ffa036864fac54
parentb4962f813ecbbed302acee7496fb4f6c27cc39b5 (diff)
downloadaccel-ppp-0614a5ed9e54982604f4c1b4a44617625312e5fd.tar.gz
accel-ppp-0614a5ed9e54982604f4c1b4a44617625312e5fd.zip
ipoe: add ipset support for l4 redirect
-rw-r--r--CMakeLists.txt5
-rw-r--r--accel-pppd/CMakeLists.txt4
-rw-r--r--accel-pppd/accel-ppp.conf3
-rw-r--r--accel-pppd/accel-ppp.conf.53
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c65
l---------accel-pppd/include/ipset.h1
-rw-r--r--accel-pppd/libnetlink/ipset.c149
-rw-r--r--accel-pppd/libnetlink/ipset.h9
-rw-r--r--config.h.in3
9 files changed, 225 insertions, 17 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c1b01c90..c0ec2a6b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,7 +6,7 @@ project(accel-ppp C)
include(cmake/cpack.cmake)
-SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fvisibility=hidden -fno-strict-aliasing -D_GNU_SOURCE -fPIC")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fvisibility=hidden -fno-strict-aliasing -D_GNU_SOURCE -fPIC -rdynamic")
IF (NOT DEFINED LIB_SUFFIX)
EXECUTE_PROCESS(
@@ -34,6 +34,7 @@ ELSE (EXISTS ${CMAKE_HOME_DIRECTORY}/.git AND NOT DEFINED IGNORE_GIT)
ENDIF (EXISTS ${CMAKE_HOME_DIRECTORY}/.git AND NOT DEFINED IGNORE_GIT)
ADD_DEFINITIONS(-DACCEL_PPP_VERSION="${ACCEL_PPP_VERSION}")
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
if (NOT BUILD_DRIVER_ONLY)
if (MEMDEBUG)
@@ -70,3 +71,5 @@ if (BUILD_IPOE_DRIVER)
add_subdirectory(drivers/ipoe)
endif (BUILD_IPOE_DRIVER)
+CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+
diff --git a/accel-pppd/CMakeLists.txt b/accel-pppd/CMakeLists.txt
index 8a7c463c..af9e5f4f 100644
--- a/accel-pppd/CMakeLists.txt
+++ b/accel-pppd/CMakeLists.txt
@@ -45,6 +45,9 @@ IF (SHAPER)
ADD_SUBDIRECTORY(shaper)
ENDIF (SHAPER)
+INCLUDE(CheckIncludeFile)
+CHECK_INCLUDE_FILE("linux/netfilter/ipset/ip_set.h" HAVE_IPSET)
+
ADD_EXECUTABLE(accel-pppd
session.c
session_backup.c
@@ -78,6 +81,7 @@ ADD_EXECUTABLE(accel-pppd
libnetlink/libnetlink.c
libnetlink/iputils.c
libnetlink/genl.c
+ libnetlink/ipset.c
pwdb.c
ipdb.c
diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf
index 127d1484..6812b0b3 100644
--- a/accel-pppd/accel-ppp.conf
+++ b/accel-pppd/accel-ppp.conf
@@ -39,7 +39,8 @@ username=ifname
lease-time=600
max-lease-time=3600
#unit-cache=1000
-l4-redirect-table=4
+#l4-redirect-table=4
+#l4-redirect-ipset=l4
#l4-redirect-on-reject=300
shared=0
ifcfg=1
diff --git a/accel-pppd/accel-ppp.conf.5 b/accel-pppd/accel-ppp.conf.5
index a79a8d6c..22d3b9dc 100644
--- a/accel-pppd/accel-ppp.conf.5
+++ b/accel-pppd/accel-ppp.conf.5
@@ -209,6 +209,9 @@ This should reduce kernel-level interface creation/deletion rate lack.
Specifies number of table. If L4-Redirect radius attribute is received and it's value is not 0 or '0' then accel-ppp will add following rule: ip rule add from client_ip table
.B n
.TP
+.BI "l4-redirect-ipset=" name
+Specifies name of ipset list. If L4-Redirect radius attribute is received and it's value is not 0 or '0' then accel-ppp will add client's ip to that ipset name.
+.TP
.BI "l4-redirect-on-reject=" n
If specified then if radius rejects access 'ip rule add from ip_addr table l4-redirect-table' rule will be created for time
.B n
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index f4701d1a..e8fbaba8 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.c
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -29,6 +29,8 @@
#include "ipdb.h"
#include "iputils.h"
+#include "ipset.h"
+
#include "connlimit.h"
#ifdef RADIUS
#include "radius.h"
@@ -65,6 +67,8 @@ static int conf_attr_l4_redirect;
#endif
static int conf_l4_redirect_table;
static int conf_l4_redirect_on_reject;
+static const char *conf_l4_redirect_ipset;
+
static const char *conf_relay;
#ifdef USE_LUA
@@ -304,7 +308,12 @@ static void l4_redirect_list_add(in_addr_t addr, int ifindex)
n->timeout = ts.tv_sec + conf_l4_redirect_on_reject;
ipoe_nl_modify(ifindex, addr, 1, NULL, NULL);
- iprule_add(addr, conf_l4_redirect_table);
+
+ if (conf_l4_redirect_table)
+ iprule_add(addr, conf_l4_redirect_table);
+
+ if (conf_l4_redirect_ipset)
+ ipset_add(conf_l4_redirect_ipset, addr);
pthread_rwlock_wrlock(&l4_list_lock);
@@ -345,7 +354,12 @@ static void l4_redirect_list_timer(struct triton_timer_t *t)
if (ts.tv_sec > n->timeout) {
list_del(&n->entry);
pthread_rwlock_unlock(&l4_list_lock);
- iprule_del(n->addr, conf_l4_redirect_table);
+
+ if (conf_l4_redirect_table)
+ iprule_del(n->addr, conf_l4_redirect_table);
+
+ if (conf_l4_redirect_ipset)
+ ipset_del(conf_l4_redirect_ipset, n->addr);
if (uc_size < conf_unit_cache && ipoe_nl_modify(n->ifindex, 0, 0, "", NULL)) {
uc = mempool_alloc(uc_pool);
@@ -372,21 +386,30 @@ static void l4_redirect_list_timer(struct triton_timer_t *t)
static void ipoe_change_l4_redirect(struct ipoe_session *ses, int del)
{
in_addr_t addr;
-
- if (conf_l4_redirect_table <= 0)
- return;
-
+
if (ses->ses.ipv4)
addr = ses->ses.ipv4->addr;
else
addr = ses->yiaddr;
+
+ if (conf_l4_redirect_table) {
+ if (del) {
+ iprule_del(addr, conf_l4_redirect_table);
+ ses->l4_redirect_set = 0;
+ } else {
+ iprule_add(addr, conf_l4_redirect_table);
+ ses->l4_redirect_set = 1;
+ }
+ }
- if (del) {
- iprule_del(addr, conf_l4_redirect_table);
- ses->l4_redirect_set = 0;
- } else {
- iprule_add(addr, conf_l4_redirect_table);
- ses->l4_redirect_set = 1;
+ if (conf_l4_redirect_ipset) {
+ if (del) {
+ ipset_del(conf_l4_redirect_ipset, addr);
+ ses->l4_redirect_set = 0;
+ } else {
+ ipset_add(conf_l4_redirect_ipset, addr);
+ ses->l4_redirect_set = 1;
+ }
}
}
@@ -1638,8 +1661,15 @@ static void l4_redirect_ctx_close(struct triton_context_t *ctx)
while (!list_empty(&l4_redirect_list)) {
n = list_entry(l4_redirect_list.next, typeof(*n), entry);
list_del(&n->entry);
- iprule_del(n->addr, conf_l4_redirect_table);
+
+ if (conf_l4_redirect_table)
+ iprule_del(n->addr, conf_l4_redirect_table);
+
+ if (conf_l4_redirect_ipset)
+ ipset_del(conf_l4_redirect_ipset, n->addr);
+
ipoe_nl_delete(n->ifindex);
+
_free(n);
}
pthread_rwlock_unlock(&l4_list_lock);
@@ -2279,10 +2309,12 @@ static void load_config(void)
conf_unit_cache = atoi(opt);
opt = conf_get_opt("ipoe", "l4-redirect-table");
- if (opt)
+ if (opt && atoi(opt) > 0)
conf_l4_redirect_table = atoi(opt);
else
- conf_l4_redirect_table = 1;
+ conf_l4_redirect_table = 0;
+
+ conf_l4_redirect_ipset = conf_get_opt("ipoe", "l4-redirect-ipset");
opt = conf_get_opt("ipoe", "l4-redirect-on-reject");
if (opt) {
@@ -2408,6 +2440,9 @@ static void ipoe_init(void)
load_config();
+ if (conf_l4_redirect_ipset)
+ ipset_flush(conf_l4_redirect_ipset);
+
cli_register_simple_cmd2(show_stat_exec, NULL, 2, "show", "stat");
triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);
diff --git a/accel-pppd/include/ipset.h b/accel-pppd/include/ipset.h
new file mode 120000
index 00000000..a4fc5e58
--- /dev/null
+++ b/accel-pppd/include/ipset.h
@@ -0,0 +1 @@
+../libnetlink/ipset.h \ No newline at end of file
diff --git a/accel-pppd/libnetlink/ipset.c b/accel-pppd/libnetlink/ipset.c
new file mode 100644
index 00000000..24f72a11
--- /dev/null
+++ b/accel-pppd/libnetlink/ipset.c
@@ -0,0 +1,149 @@
+#include "config.h"
+
+#ifdef HAVE_IPSET
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <net/if_arp.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/uio.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/ipset/ip_set.h>
+
+#include "triton.h"
+#include "log.h"
+
+#include "libnetlink.h"
+#include "ipset.h"
+
+#include "memdebug.h"
+
+static int __ipset_cmd(const char *name, in_addr_t addr, int cmd, int flags)
+{
+ struct rtnl_handle rth;
+ struct req {
+ struct nlmsghdr n;
+ struct nfgenmsg nf;
+ char buf[1024];
+ } req;
+ struct rtattr *tail1, *tail2;
+ uint8_t protocol = IPSET_PROTOCOL;
+
+ if (rtnl_open_byproto(&rth, 0, NETLINK_NETFILTER)) {
+ log_error("ipset: cannot open rtnetlink\n");
+ return -1;
+ }
+
+ memset(&req, 0, sizeof(req) - 1024);
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nfgenmsg));
+ req.n.nlmsg_flags = flags;
+ req.n.nlmsg_type = cmd | (NFNL_SUBSYS_IPSET << 8);
+ req.nf.nfgen_family = AF_INET;
+ req.nf.version = NFNETLINK_V0;
+ req.nf.res_id = 0;
+
+ addattr_l(&req.n, 1024, IPSET_ATTR_PROTOCOL, &protocol, 1);
+ addattr_l(&req.n, 1024, IPSET_ATTR_SETNAME, name, strlen(name) + 1);
+
+ tail1 = addattr_nest(&req.n, MAX_MSG, IPSET_ATTR_DATA | NLA_F_NESTED);
+
+ tail2 = addattr_nest(&req.n, MAX_MSG, IPSET_ATTR_IP | NLA_F_NESTED);
+ addattr32(&req.n, 1024, IPSET_ATTR_IPADDR_IPV4 | NLA_F_NET_BYTEORDER, addr);
+ addattr_nest_end(&req.n, tail2);
+
+ addattr_nest_end(&req.n, tail1);
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
+ goto out_err;
+
+ rtnl_close(&rth);
+
+ return 0;
+
+out_err:
+ rtnl_close(&rth);
+
+ return -1;
+
+}
+
+int __export ipset_add(const char *name, in_addr_t addr)
+{
+ return __ipset_cmd(name, addr, IPSET_CMD_ADD, NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL);
+}
+
+int __export ipset_del(const char *name, in_addr_t addr)
+{
+ return __ipset_cmd(name, addr, IPSET_CMD_DEL, NLM_F_REQUEST | NLM_F_ACK);
+}
+
+int __export ipset_flush(const char *name)
+{
+ struct rtnl_handle rth;
+ struct req {
+ struct nlmsghdr n;
+ struct nfgenmsg nf;
+ char buf[1024];
+ } req;
+ uint8_t protocol = IPSET_PROTOCOL;
+
+ if (rtnl_open_byproto(&rth, 0, NETLINK_NETFILTER)) {
+ log_error("ipset: cannot open rtnetlink\n");
+ return -1;
+ }
+
+ memset(&req, 0, sizeof(req) - 1024);
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nfgenmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ req.n.nlmsg_type = IPSET_CMD_FLUSH | (NFNL_SUBSYS_IPSET << 8);
+ req.nf.nfgen_family = AF_INET;
+ req.nf.version = NFNETLINK_V0;
+ req.nf.res_id = 0;
+
+ addattr_l(&req.n, 1024, IPSET_ATTR_PROTOCOL, &protocol, 1);
+ addattr_l(&req.n, 1024, IPSET_ATTR_SETNAME, name, strlen(name) + 1);
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
+ goto out_err;
+
+ rtnl_close(&rth);
+
+ return 0;
+
+out_err:
+ rtnl_close(&rth);
+
+ return -1;
+}
+
+#else
+
+#include <netinet/in.h>
+#include "triton.h"
+
+int __export ipset_add(const char *name, in_addr_t addr)
+{
+ return -1;
+}
+
+int __export ipset_del(const char *name, in_addr_t addr)
+{
+ return -1;
+}
+
+int __export ipset_flush(const char *name)
+{
+ return -1;
+}
+
+#endif
diff --git a/accel-pppd/libnetlink/ipset.h b/accel-pppd/libnetlink/ipset.h
new file mode 100644
index 00000000..cd5523dc
--- /dev/null
+++ b/accel-pppd/libnetlink/ipset.h
@@ -0,0 +1,9 @@
+#ifndef __IPSET_H
+#define __IPSET_H
+
+int ipset_add(const char *name, in_addr_t addr);
+int ipset_del(const char *name, in_addr_t addr);
+int ipset_flush(const char *name);
+
+#endif
+
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 00000000..0c8ab8cf
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,3 @@
+//#cmakedefine ACCEL_PPP_VERSION "${ACCEL_PPP_VERSION}"
+//#cmakedefine RADIUS
+#cmakedefine HAVE_IPSET