diff options
author | Kozlov Dmitry <xeb@mail.ru> | 2013-08-28 17:42:10 +0400 |
---|---|---|
committer | Kozlov Dmitry <xeb@mail.ru> | 2013-08-28 17:44:29 +0400 |
commit | 0614a5ed9e54982604f4c1b4a44617625312e5fd (patch) | |
tree | bcccfb25e5e42f49b83387f6e3ffa036864fac54 | |
parent | b4962f813ecbbed302acee7496fb4f6c27cc39b5 (diff) | |
download | accel-ppp-0614a5ed9e54982604f4c1b4a44617625312e5fd.tar.gz accel-ppp-0614a5ed9e54982604f4c1b4a44617625312e5fd.zip |
ipoe: add ipset support for l4 redirect
-rw-r--r-- | CMakeLists.txt | 5 | ||||
-rw-r--r-- | accel-pppd/CMakeLists.txt | 4 | ||||
-rw-r--r-- | accel-pppd/accel-ppp.conf | 3 | ||||
-rw-r--r-- | accel-pppd/accel-ppp.conf.5 | 3 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.c | 65 | ||||
l--------- | accel-pppd/include/ipset.h | 1 | ||||
-rw-r--r-- | accel-pppd/libnetlink/ipset.c | 149 | ||||
-rw-r--r-- | accel-pppd/libnetlink/ipset.h | 9 | ||||
-rw-r--r-- | config.h.in | 3 |
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 |