summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--accel-pppd/accel-ppp.conf.53
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c89
2 files changed, 74 insertions, 18 deletions
diff --git a/accel-pppd/accel-ppp.conf.5 b/accel-pppd/accel-ppp.conf.5
index 4aca90f..ac2abf6 100644
--- a/accel-pppd/accel-ppp.conf.5
+++ b/accel-pppd/accel-ppp.conf.5
@@ -214,6 +214,9 @@ If specified then if radius rejects access 'ip rule add from ip_addr table l4-re
.B n
seconds.
.TP
+.BI "gw-ip-address="x.x.x.x/mask
+Specifies address to be used as server ip address if radius can assign only client address. In such case if client address is matched network and mask then specified address and mask will be used. You can specify multiple such options.
+.TP
.BI "shared=" 0|1
Specifies default value for per-interface
.B shared
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index b0d5201..18965d8 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.c
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -69,7 +69,7 @@ static const char *conf_lua_username_func;
#endif
static int conf_offer_timeout = 3;
-static in_addr_t conf_gw_address;
+static LIST_HEAD(conf_gw_addr);
static int conf_netmask = 24;
static int conf_lease_time = 600;
static int conf_lease_timeout = 660;
@@ -83,33 +83,35 @@ static mempool_t ses_pool;
static LIST_HEAD(serv_list);
-struct ifaddr
-{
+struct ifaddr {
struct list_head entry;
in_addr_t addr;
int refs;
};
-struct iplink_arg
-{
+struct iplink_arg {
pcre *re;
const char *opt;
};
-struct unit_cache
-{
+struct unit_cache {
struct list_head entry;
int ifindex;
};
-struct l4_redirect
-{
+struct l4_redirect {
struct list_head entry;
int ifindex;
in_addr_t addr;
time_t timeout;
};
+struct gw_addr {
+ struct list_head entry;
+ in_addr_t addr;
+ int mask;
+};
+
static pthread_mutex_t uc_lock = PTHREAD_MUTEX_INITIALIZER;
static LIST_HEAD(uc_list);
static int uc_size;
@@ -472,6 +474,22 @@ static void ipoe_session_start(struct ipoe_session *ses)
__ipoe_session_start(ses);
}
+static void find_gw_addr(struct ipoe_session *ses)
+{
+ struct gw_addr *a;
+
+ list_for_each_entry(a, &conf_gw_addr, entry) {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ if ((ses->yiaddr & ((1<<a->mask) - 1)) == (a->addr & ((1<<a->mask) - 1))) {
+ ses->siaddr = a->addr;
+ ses->mask = a->mask;
+ return;
+ }
+#else
+#endif
+ }
+}
+
static void __ipoe_session_start(struct ipoe_session *ses)
{
if (!ses->yiaddr) {
@@ -487,9 +505,6 @@ static void __ipoe_session_start(struct ipoe_session *ses)
ses->mask = conf_netmask;
if (ses->ses.ipv4) {
- if (conf_gw_address)
- ses->ses.ipv4->addr = conf_gw_address;
-
if (!ses->mask)
ses->mask = ses->ses.ipv4->mask;
@@ -519,6 +534,9 @@ static void __ipoe_session_start(struct ipoe_session *ses)
if (!ses->siaddr && ses->serv->dhcpv4_relay)
ses->siaddr = ses->serv->dhcpv4_relay->giaddr;
+ if (!ses->siaddr)
+ find_gw_addr(ses);
+
if (!ses->siaddr) {
log_ppp_error("can't determine Server-ID\n");
ap_session_terminate(&ses->ses, TERM_NAS_ERROR, 0);
@@ -1855,6 +1873,46 @@ static void load_local_nets(struct conf_sect_t *sect)
}
}
+static void load_gw_addr(struct conf_sect_t *sect)
+{
+ struct conf_option_t *opt;
+ struct gw_addr *a;
+ char addr[17];
+ char *ptr;
+
+ while (!list_empty(&conf_gw_addr)) {
+ a = list_entry(conf_gw_addr.next, typeof(*a), entry);
+ list_del(&a->entry);
+ _free(a);
+ }
+
+ list_for_each_entry(opt, &sect->items, entry) {
+ if (strcmp(opt->name, "gw-ip-address"))
+ continue;
+ if (!opt->val)
+ continue;
+
+ a = _malloc(sizeof(*a));
+ ptr = strchr(opt->val, '/');
+ if (ptr) {
+ memcpy(addr, opt->val, ptr - opt->val);
+ addr[ptr - opt->val] = 0;
+ a->addr = inet_addr(addr);
+ a->mask = atoi(ptr + 1);
+ } else {
+ a->addr = inet_addr(opt->val);
+ a->mask = 32;
+ }
+
+ if (a->addr == 0xffffffff || a->mask < 1 || a->mask > 32) {
+ log_error("ipoe: failed to parse '%s=%s'\n", opt->name, opt->val);
+ _free(a);
+ continue;
+ }
+ list_add_tail(&a->entry, &conf_gw_addr);
+ }
+}
+
#ifdef RADIUS
static void parse_conf_rad_attr(const char *opt, int *val)
{
@@ -1908,12 +1966,6 @@ static void load_config(void)
log_emerg("ipoe: unknown username value '%s'\n", opt);
}
- opt = conf_get_opt("ipoe", "gw-ip-address");
- if (opt)
- conf_gw_address = inet_addr(opt);
- else
- conf_gw_address = 0;
-
opt = conf_get_opt("ipoe", "netmask");
if (opt) {
conf_netmask = atoi(opt);
@@ -2027,6 +2079,7 @@ static void load_config(void)
load_interfaces(s);
load_local_nets(s);
+ load_gw_addr(s);
}
static struct triton_context_t l4_redirect_ctx = {