diff options
author | Kozlov Dmitry <xeb@mail.ru> | 2012-07-19 19:09:24 +0400 |
---|---|---|
committer | Kozlov Dmitry <xeb@mail.ru> | 2012-07-19 19:09:24 +0400 |
commit | a60d08c8ca66de1844a430cc487a725e4c0e0d54 (patch) | |
tree | 2c05a0acafefbfd22c2d8cc4093ae7ba6946b8c1 /accel-pppd/ctrl/ipoe/ipoe.c | |
parent | 09b155588131d8ed6f380aec467d0fa7749933b8 (diff) | |
download | accel-ppp-a60d08c8ca66de1844a430cc487a725e4c0e0d54.tar.gz accel-ppp-a60d08c8ca66de1844a430cc487a725e4c0e0d54.zip |
ipoe: implemented L4-Redirect radius attribute
ipoe: implemented client address, router address and mask to be passed via radius
Diffstat (limited to 'accel-pppd/ctrl/ipoe/ipoe.c')
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.c | 153 |
1 files changed, 149 insertions, 4 deletions
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index 69ffe36..711dca3 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -30,6 +30,9 @@ #include "iplink.h" #include "connlimit.h" +#ifdef RADIUS +#include "radius.h" +#endif #include "ipoe.h" @@ -49,6 +52,13 @@ static int conf_ifcfg = 1; //static int conf_dhcpv6; static int conf_username; static int conf_unit_cache; +#ifdef RADIUS +static int conf_attr_dhcp_client_ip; +static int conf_attr_dhcp_router_ip; +static int conf_attr_dhcp_mask; +static int conf_attr_l4_redirect; +#endif +static int conf_l4_redirect_table; #ifdef USE_LUA static const char *conf_lua_username_func; @@ -182,6 +192,29 @@ static void ipoe_session_set_username(struct ipoe_session *ses) ses->ses.username = _strdup(ses->ses.ifname); } +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 (del) + iprule_del(addr, conf_l4_redirect_table); + else + iprule_add(addr, conf_l4_redirect_table); +} + +static void ipoe_change_addr(struct ipoe_session *ses, in_addr_t newaddr) +{ + +} + static void ipoe_session_start(struct ipoe_session *ses) { int r; @@ -256,9 +289,11 @@ static void ipoe_session_start(struct ipoe_session *ses) return; } - dhcpv4_get_ip(ses->serv->dhcpv4, &ses->yiaddr, &ses->siaddr, &ses->mask); - if (ses->yiaddr) - ses->dhcp_addr = 1; + if (!ses->yiaddr) { + dhcpv4_get_ip(ses->serv->dhcpv4, &ses->yiaddr, &ses->siaddr, &ses->mask); + if (ses->yiaddr) + ses->dhcp_addr = 1; + } ses->ses.ipv4 = ipdb_get_ipv4(&ses->ses); /*if (!ses->ses.ipv4) { @@ -390,6 +425,9 @@ static void ipoe_session_activate(struct ipoe_session *ses) if (ses->serv->opt_ifcfg) ipoe_ifcfg_add(ses); + + if (ses->l4_redirect) + ipoe_change_l4_redirect(ses, 0); ap_session_activate(&ses->ses); @@ -494,6 +532,11 @@ static void ipoe_session_finished(struct ap_session *s) static void ipoe_session_terminate(struct ap_session *s, int hard) { + struct ipoe_session *ses = container_of(s, typeof(*ses), ses); + + if (ses->l4_redirect) + ipoe_change_l4_redirect(ses, 1); + ap_session_finished(s); } @@ -814,6 +857,62 @@ void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph) } } +#ifdef RADIUS +static void ev_radius_access_accept(struct ev_radius_t *ev) +{ + struct ipoe_session *ses = container_of(ev->ses, typeof(*ses), ses); + struct rad_attr_t *attr; + + if (ev->ses->ctrl->type != CTRL_TYPE_IPOE) + return; + + list_for_each_entry(attr, &ev->reply->attrs, entry) { + if (attr->attr->id == conf_attr_dhcp_client_ip) + ses->yiaddr = attr->val.ipaddr; + else if (attr->attr->id == conf_attr_dhcp_router_ip) + ses->siaddr = attr->val.ipaddr; + else if (attr->attr->id == conf_attr_dhcp_mask) { + if (attr->val.integer > 0 && attr->val.integer < 31) + ses->mask = attr->val.integer; + } else if (attr->attr->id == conf_attr_l4_redirect) { + if (attr->attr->type == ATTR_TYPE_STRING) { + if (attr->len && attr->val.string[0] != '0') + ses->l4_redirect = 1; + } else if (attr->val.integer != 0) + ses->l4_redirect = 1; + } + } +} + +static void ev_radius_coa(struct ev_radius_t *ev) +{ + struct ipoe_session *ses = container_of(ev->ses, typeof(*ses), ses); + struct rad_attr_t *attr; + int l4_redirect; + + if (ev->ses->ctrl->type != CTRL_TYPE_IPOE) + return; + + l4_redirect = ses->l4_redirect; + + list_for_each_entry(attr, &ev->request->attrs, entry) { + if (attr->attr->id == conf_attr_l4_redirect) { + if (attr->attr->type == ATTR_TYPE_STRING) + ses->l4_redirect = attr->len && attr->val.string[0] != '0'; + else + ses->l4_redirect = ((unsigned int)attr->val.integer) > 0; + } else if (strcmp(attr->attr->name, "Framed-IP-Address") == 0) { + if (ses->ses.ipv4 && ses->ses.ipv4->peer_addr != attr->val.ipaddr) + ipoe_change_addr(ses, attr->val.ipaddr); + } + } + + //if (l4_redirect && !ses->l4_redirect) || (!l4_redirect && ses->l4_redirect)) + if (l4_redirect != ses->l4_redirect) + ipoe_change_l4_redirect(ses, l4_redirect); +} +#endif + static void ipoe_serv_close(struct triton_context_t *ctx) { struct ipoe_serv *serv = container_of(ctx, typeof(*serv), ctx); @@ -1155,6 +1254,35 @@ static void load_local_nets(struct conf_sect_t *sect) } } +#ifdef RADIUS +static void parse_conf_rad_attr(const char *opt, int *val) +{ + struct rad_dict_attr_t *attr; + + opt = conf_get_opt("ipoe", opt); + + if (opt) { + if (atoi(opt) > 0) + *val = atoi(opt); + else { + attr = rad_dict_find_attr(opt); + if (attr) + *val = attr->id; + else + log_emerg("ipoe: couldn't find '%s' in dictionary\n", opt); + } + } else + *val = -1; +} +static void load_radius_attrs(void) +{ + parse_conf_rad_attr("attr-dhcp-client-ip", &conf_attr_dhcp_client_ip); + parse_conf_rad_attr("attr-dhcp-router-ip", &conf_attr_dhcp_router_ip); + parse_conf_rad_attr("attr-dhcp-mask", &conf_attr_dhcp_mask); + parse_conf_rad_attr("attr-l4-redirect", &conf_attr_l4_redirect); +} +#endif + static void load_config(void) { const char *opt; @@ -1210,6 +1338,12 @@ static void load_config(void) if (opt) conf_unit_cache = atoi(opt); + opt = conf_get_opt("ipoe", "l4-redirect-table"); + if (opt) + conf_l4_redirect_table = atoi(opt); + else + conf_l4_redirect_table = 0; + opt = conf_get_opt("ipoe", "shared"); if (opt) conf_shared = atoi(opt); @@ -1248,6 +1382,11 @@ static void load_config(void) if (!conf_dhcpv4 && !conf_up) conf_dhcpv4 = 1; +#ifdef RADIUS + if (triton_module_loaded("radius")) + load_radius_attrs(); +#endif + load_interfaces(s); load_local_nets(s); } @@ -1262,6 +1401,12 @@ static void ipoe_init(void) cli_register_simple_cmd2(show_stat_exec, NULL, 2, "show", "stat"); triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config); + +#ifdef RADIUS + if (triton_module_loaded("radius")) + triton_event_register_handler(EV_RADIUS_ACCESS_ACCEPT, (triton_event_func)ev_radius_access_accept); + triton_event_register_handler(EV_RADIUS_COA, (triton_event_func)ev_radius_coa); +#endif } -DEFINE_INIT(20, ipoe_init); +DEFINE_INIT(52, ipoe_init); |