diff options
author | Kozlov Dmitry <dima@server> | 2010-09-09 18:26:02 +0400 |
---|---|---|
committer | Kozlov Dmitry <dima@server> | 2010-09-09 18:29:47 +0400 |
commit | 35d38d2c3f3db22216d43604b8750ecb6089e525 (patch) | |
tree | f599fea448c4aacdd96cabf10fee88aa7bdb57aa /accel-pptpd | |
parent | eac0adf4b2b038690c761a126cb3e55a888060df (diff) | |
download | accel-ppp-35d38d2c3f3db22216d43604b8750ecb6089e525.tar.gz accel-ppp-35d38d2c3f3db22216d43604b8750ecb6089e525.zip |
iprange: implemneted modules iprange to validate ip addresses of controlling connection and tunnel
It will check that ip address of tunnel is not in range of clients ip addresses.
This will avoid kernel softlockups due to loopback occured.
Diffstat (limited to 'accel-pptpd')
-rw-r--r-- | accel-pptpd/CMakeLists.txt | 2 | ||||
-rw-r--r-- | accel-pptpd/accel-pptpd.conf | 8 | ||||
-rw-r--r-- | accel-pptpd/ctrl/pptp.c | 8 | ||||
l--------- | accel-pptpd/include/iprange.h | 1 | ||||
-rw-r--r-- | accel-pptpd/iprange.c | 134 | ||||
-rw-r--r-- | accel-pptpd/iprange.h | 10 | ||||
-rw-r--r-- | accel-pptpd/ppp/ipcp_opt_ipaddr.c | 9 | ||||
-rw-r--r-- | accel-pptpd/radius/CMakeLists.txt | 2 | ||||
-rw-r--r-- | accel-pptpd/radius/pd_coa.c | 48 | ||||
-rw-r--r-- | accel-pptpd/radius/radius.c | 10 | ||||
-rw-r--r-- | accel-pptpd/radius/radius.h | 4 |
11 files changed, 202 insertions, 34 deletions
diff --git a/accel-pptpd/CMakeLists.txt b/accel-pptpd/CMakeLists.txt index 041c668..729b4e2 100644 --- a/accel-pptpd/CMakeLists.txt +++ b/accel-pptpd/CMakeLists.txt @@ -28,6 +28,8 @@ ADD_EXECUTABLE(pptpd log.c pwdb.c ipdb.c + + iprange.c main.c ) diff --git a/accel-pptpd/accel-pptpd.conf b/accel-pptpd/accel-pptpd.conf index 26bb27d..9d5aa9b 100644 --- a/accel-pptpd/accel-pptpd.conf +++ b/accel-pptpd/accel-pptpd.conf @@ -24,5 +24,11 @@ nas-ip-address=127.0.0.1 gw-ip-address=192.168.100.100 auth_server=127.0.0.1:1812,testing123 acct_server=127.0.0.1:1813,testing123 -pd_coa_secret=testing123 +dm_coa_secret=testing123 verbose=1 + +[client-ip-range] +192.168.10.20-20 + +[ip-pool] +192.168.100.200/24 diff --git a/accel-pptpd/ctrl/pptp.c b/accel-pptpd/ctrl/pptp.c index 3a3c242..38f8473 100644 --- a/accel-pptpd/ctrl/pptp.c +++ b/accel-pptpd/ctrl/pptp.c @@ -17,7 +17,7 @@ #include "triton.h" #include "log.h" #include "ppp.h" - +#include "iprange.h" #define STATE_IDLE 0 #define STATE_ESTB 1 @@ -477,6 +477,12 @@ static int pptp_connect(struct triton_md_handler_t *h) log_info("pptp: new connection from %s\n", inet_ntoa(addr.sin_addr)); + if (iprange_client_check(addr.sin_addr.s_addr)) { + log_warn("pptp: IP is out of client-ip-range, droping connection...\n"); + close(sock); + continue; + } + if (fcntl(sock, F_SETFL, O_NONBLOCK)) { log_error("pptp: failed to set nonblocking mode: %s, closing connection...\n", strerror(errno)); close(sock); diff --git a/accel-pptpd/include/iprange.h b/accel-pptpd/include/iprange.h new file mode 120000 index 0000000..b8c2c43 --- /dev/null +++ b/accel-pptpd/include/iprange.h @@ -0,0 +1 @@ +../iprange.h
\ No newline at end of file diff --git a/accel-pptpd/iprange.c b/accel-pptpd/iprange.c new file mode 100644 index 0000000..000e6e6 --- /dev/null +++ b/accel-pptpd/iprange.c @@ -0,0 +1,134 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <unistd.h> + +#include "triton.h" +#include "list.h" + +#include "iprange.h" + +struct iprange_t +{ + struct list_head entry; + uint32_t prefix; + uint32_t mask; + uint32_t end; +}; + +static LIST_HEAD(client_ranges); +//static LIST_HEAD(tunnel_ranges); + +//parses ranges like x.x.x.x/mask +static struct iprange_t *parse1(const char *str) +{ + int n,f1,f2,f3,f4,m; + struct iprange_t *r; + + n = sscanf(str, "%u.%u.%u.%u/%u",&f1, &f2, &f3, &f4, &m); + if (n != 5) + return NULL; + if (f1 > 255) + return NULL; + if (f1 > 255) + return NULL; + if (f1 > 255) + return NULL; + if (f1 > 255) + return NULL; + if (m == 0 || m > 32) + return NULL; + + r = malloc(sizeof(*r)); + r->prefix = (f4 << 24) | (f3 << 16) | (f2 << 8) | f1; + r->mask = 0; + + for (n = 0; n < m ; n++) + r->mask |= 1 << n; + + return r; +} + +//parses ranges like x.x.x.x-y +static struct iprange_t *parse2(const char *str) +{ + int n,f1,f2,f3,f4,m; + struct iprange_t *r; + + n = sscanf(str, "%u.%u.%u.%u-%u",&f1, &f2, &f3, &f4, &m); + if (n != 5) + return NULL; + if (f1 > 255) + return NULL; + if (f2 > 255) + return NULL; + if (f3 > 255) + return NULL; + if (f4 > 255) + return NULL; + if (m < f4 || m > 255) + return NULL; + + r = malloc(sizeof(*r)); + r->prefix = (f4 << 24) | (f3 << 16) | (f2 << 8) | f1; + r->end = (m << 24) | (f2 << 16) | (f3 << 8) | f1; + r->mask = 0; + + return r; +} + +static void load_ranges(struct list_head *list, const char *conf_sect) +{ + struct conf_sect_t *s = conf_get_section(conf_sect); + struct conf_option_t *opt; + struct iprange_t *r; + + if (!s) { + fprintf(stderr, "iprange: section '%s' not found in config file, pptp and l2tp probably will not work...\n", conf_sect); + return; + } + + list_for_each_entry(opt, &s->items, entry) { + r = parse1(opt->name); + if (!r) + r = parse2(opt->name); + if (!r) { + fprintf(stderr, "iprange: cann't parse '%s' in '%s'\n", opt->name, conf_sect); + _exit(EXIT_FAILURE); + } + list_add_tail(&r->entry, list); + } +} + +static int check_range(struct list_head *list, in_addr_t ipaddr) +{ + struct iprange_t *r; + + list_for_each_entry(r, list, entry) { + if (r->mask) { + if ((r->prefix & r->mask) == (ipaddr & r->mask)) + return 0; + } else { + if (ipaddr >= r->prefix && ipaddr <= r->end) + return 0; + } + } + + return -1; +} + +int __export iprange_client_check(in_addr_t ipaddr) +{ + return check_range(&client_ranges, ipaddr); +} +/*int __export iprange_tunnel_check(in_addr_t ipaddr) +{ + return check_range(&tunnel_ranges, ipaddr); +}*/ + +static void __init iprange_init(void) +{ + load_ranges(&client_ranges, "client-ip-range"); + //load_ranges(&tunnel_ranges, "tunnel-ip-range"); +} + diff --git a/accel-pptpd/iprange.h b/accel-pptpd/iprange.h new file mode 100644 index 0000000..88a2486 --- /dev/null +++ b/accel-pptpd/iprange.h @@ -0,0 +1,10 @@ +#ifndef __IPRANGE_H +#define __IPRANGE_H + +#include <netinet/in.h> + +int iprange_client_check(in_addr_t ipaddr); +int iprange_tunnel_check(in_addr_t ipaddr); + +#endif + diff --git a/accel-pptpd/ppp/ipcp_opt_ipaddr.c b/accel-pptpd/ppp/ipcp_opt_ipaddr.c index ddfb3d2..6e52cfa 100644 --- a/accel-pptpd/ppp/ipcp_opt_ipaddr.c +++ b/accel-pptpd/ppp/ipcp_opt_ipaddr.c @@ -10,6 +10,7 @@ #include "ppp_ipcp.h" #include "log.h" #include "ipdb.h" +#include "iprange.h" static struct ipcp_option_t *ipaddr_init(struct ppp_ipcp_t *ipcp); static void ipaddr_free(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt); @@ -65,6 +66,14 @@ static int ipaddr_send_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *o log_warn("ppp:ipcp: no free IP address\n"); return -1; } + if (!iprange_client_check(ipaddr_opt->peer_addr)) { + log_warn("ppp:ipcp: to avoid hard loops requested IP cannot be assigned (%i.%i.%i.%i)\n", + ipaddr_opt->peer_addr&0xff, + (ipaddr_opt->peer_addr >> 8)&0xff, + (ipaddr_opt->peer_addr >> 16)&0xff, + (ipaddr_opt->peer_addr >> 24)&0xff); + return -1; + } opt32->hdr.id=CI_ADDR; opt32->hdr.len=6; diff --git a/accel-pptpd/radius/CMakeLists.txt b/accel-pptpd/radius/CMakeLists.txt index ac8a3a9..c8c44f8 100644 --- a/accel-pptpd/radius/CMakeLists.txt +++ b/accel-pptpd/radius/CMakeLists.txt @@ -6,7 +6,7 @@ SET(sources packet.c auth.c acct.c - pd_coa.c + dm_coa.c ) ADD_LIBRARY(radius SHARED ${sources}) diff --git a/accel-pptpd/radius/pd_coa.c b/accel-pptpd/radius/pd_coa.c index b19575c..0d2f405 100644 --- a/accel-pptpd/radius/pd_coa.c +++ b/accel-pptpd/radius/pd_coa.c @@ -18,13 +18,13 @@ #define PD_COA_PORT 3799 -struct pd_coa_serv_t +struct dm_coa_serv_t { struct triton_context_t ctx; struct triton_md_handler_t hnd; }; -static int pd_coa_check_RA(struct rad_packet_t *pack, const char *secret) +static int dm_coa_check_RA(struct rad_packet_t *pack, const char *secret) { uint8_t RA[16]; MD5_CTX ctx; @@ -41,7 +41,7 @@ static int pd_coa_check_RA(struct rad_packet_t *pack, const char *secret) return memcmp(RA, pack->buf + 4, 16); } -static void pd_coa_set_RA(struct rad_packet_t *pack, const char *secret) +static void dm_coa_set_RA(struct rad_packet_t *pack, const char *secret) { MD5_CTX ctx; @@ -53,21 +53,21 @@ static void pd_coa_set_RA(struct rad_packet_t *pack, const char *secret) static void disconnect_request(struct radius_pd_t *rpd) { - rad_packet_free(rpd->pd_coa_req); - rpd->pd_coa_req = NULL; + rad_packet_free(rpd->dm_coa_req); + rpd->dm_coa_req = NULL; ppp_terminate(rpd->ppp, 0); } static void coa_request(struct radius_pd_t *rpd) { - rad_packet_free(rpd->pd_coa_req); - rpd->pd_coa_req = NULL; + rad_packet_free(rpd->dm_coa_req); + rpd->dm_coa_req = NULL; /// TODO: CoA handling } -static int pd_coa_read(struct triton_md_handler_t *h) +static int dm_coa_read(struct triton_md_handler_t *h) { struct rad_packet_t *pack; struct rad_packet_t *reply = NULL; @@ -82,12 +82,12 @@ static int pd_coa_read(struct triton_md_handler_t *h) return 0; if (pack->code != CODE_DISCONNECT_REQUEST && pack->code != CODE_COA_REQUEST) { - log_warn("radius:pd_coa: unexpected code (%i) received\n", pack->code); + log_warn("radius:dm_coa: unexpected code (%i) received\n", pack->code); goto out_err_no_reply; } - if (pd_coa_check_RA(pack, conf_pd_coa_secret)) { - log_warn("radius:pd_coa: RA validation failed\n"); + if (dm_coa_check_RA(pack, conf_dm_coa_secret)) { + log_warn("radius:dm_coa: RA validation failed\n"); goto out_err_no_reply; } @@ -99,19 +99,19 @@ static int pd_coa_read(struct triton_md_handler_t *h) } if (rad_check_nas_pack(pack)) { - log_warn("radius:pd_coa: NAS identification failed\n"); + log_warn("radius:dm_coa: NAS identification failed\n"); err_code = 403; goto out_err; } rpd = rad_find_session_pack(pack); if (!rpd) { - log_warn("radius:pd_coa: session not found\n"); + log_warn("radius:dm_coa: session not found\n"); err_code = 503; goto out_err; } - rpd->pd_coa_req = pack; + rpd->dm_coa_req = pack; if (pack->code == CODE_DISCONNECT_REQUEST) triton_context_call(rpd->ppp->ctrl->ctx, (void (*)(void *))disconnect_request, rpd); @@ -124,7 +124,7 @@ static int pd_coa_read(struct triton_md_handler_t *h) reply->id = pack->id; if (rad_packet_build(reply, RA)) goto out_err_no_reply; - pd_coa_set_RA(reply, conf_pd_coa_secret); + dm_coa_set_RA(reply, conf_dm_coa_secret); if (conf_verbose) { log_debug("send "); rad_packet_print(reply, log_debug); @@ -140,7 +140,7 @@ out_err: reply->id = pack->id; if (rad_packet_build(reply, RA)) goto out_err_no_reply; - pd_coa_set_RA(reply, conf_pd_coa_secret); + dm_coa_set_RA(reply, conf_dm_coa_secret); if (conf_verbose) { log_debug("send "); rad_packet_print(reply, log_debug); @@ -154,16 +154,16 @@ out_err_no_reply: return 0; } -static void pd_coa_close(struct triton_context_t *ctx) +static void dm_coa_close(struct triton_context_t *ctx) { - struct pd_coa_serv_t *serv = container_of(ctx, typeof(*serv), ctx); + struct dm_coa_serv_t *serv = container_of(ctx, typeof(*serv), ctx); triton_md_unregister_handler(&serv->hnd); close(serv->hnd.fd); } -static struct pd_coa_serv_t serv = { - .ctx.close = pd_coa_close, - .hnd.read = pd_coa_read, +static struct dm_coa_serv_t serv = { + .ctx.close = dm_coa_close, + .hnd.read = dm_coa_read, }; static void __init init(void) @@ -172,7 +172,7 @@ static void __init init(void) serv.hnd.fd = socket (PF_INET, SOCK_DGRAM, 0); if (serv.hnd.fd < 0) { - log_error("radius:pd_coa: socket: %s\n", strerror(errno)); + log_error("radius:dm_coa: socket: %s\n", strerror(errno)); return; } addr.sin_family = AF_INET; @@ -182,13 +182,13 @@ static void __init init(void) else addr.sin_addr.s_addr = htonl (INADDR_ANY); if (bind (serv.hnd.fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) { - log_error("radius:pd_coa: bind: %s\n", strerror(errno)); + log_error("radius:dm_coa: bind: %s\n", strerror(errno)); close(serv.hnd.fd); return; } if (fcntl(serv.hnd.fd, F_SETFL, O_NONBLOCK)) { - log_error("radius:pd_coa: failed to set nonblocking mode: %s\n", strerror(errno)); + log_error("radius:dm_coa: failed to set nonblocking mode: %s\n", strerror(errno)); close(serv.hnd.fd); return; } diff --git a/accel-pptpd/radius/radius.c b/accel-pptpd/radius/radius.c index de64f6b..d709963 100644 --- a/accel-pptpd/radius/radius.c +++ b/accel-pptpd/radius/radius.c @@ -30,7 +30,7 @@ char *conf_auth_secret; char *conf_acct_server; int conf_acct_server_port = 1813; char *conf_acct_secret; -char *conf_pd_coa_secret; +char *conf_dm_coa_secret; static LIST_HEAD(sessions); static pthread_rwlock_t sessions_lock = PTHREAD_RWLOCK_INITIALIZER; @@ -137,8 +137,8 @@ static void ppp_finished(struct ppp_notified_t *n, struct ppp_t *ppp) pthread_mutex_unlock(&rpd->lock); pthread_rwlock_unlock(&sessions_lock); - if (rpd->pd_coa_req) - rad_packet_free(rpd->pd_coa_req); + if (rpd->dm_coa_req) + rad_packet_free(rpd->dm_coa_req); list_del(&rpd->pd.entry); free(rpd); @@ -308,9 +308,9 @@ static void __init radius_init(void) _exit(EXIT_FAILURE); } - opt = conf_get_opt("radius", "pd_coa_secret"); + opt = conf_get_opt("radius", "dm_coa_secret"); if (opt) - conf_pd_coa_secret = opt; + conf_dm_coa_secret = opt; opt = conf_get_opt("radius", "dictionary"); if (!opt) { diff --git a/accel-pptpd/radius/radius.h b/accel-pptpd/radius/radius.h index 9728a4a..cededbe 100644 --- a/accel-pptpd/radius/radius.h +++ b/accel-pptpd/radius/radius.h @@ -40,7 +40,7 @@ struct radius_pd_t struct rad_req_t *acct_req; struct triton_timer_t acct_interim_timer; - struct rad_packet_t *pd_coa_req; + struct rad_packet_t *dm_coa_req; in_addr_t ipaddr; int acct_interim_interval; @@ -120,7 +120,7 @@ extern int conf_auth_server_port; extern char *conf_acct_server; extern char *conf_acct_secret; extern int conf_acct_server_port; -extern char *conf_pd_coa_secret; +extern char *conf_dm_coa_secret; int rad_check_nas_pack(struct rad_packet_t *pack); struct radius_pd_t *rad_find_session(const char *sessionid, const char *username, int port_id, in_addr_t ipaddr); |