#include #include #include #include #include #include #include #include "linux_ppp.h" #include "ppp.h" #include "ppp_ipcp.h" #include "ppp_ccp.h" #include "log.h" #include "ipdb.h" #include "iprange.h" #include "events.h" #include "memdebug.h" static int conf_check_exists; 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); static int ipaddr_send_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr); static int ipaddr_send_conf_nak(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr); static int ipaddr_recv_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr); //static int ipaddr_recv_conf_ack(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr); static void ipaddr_print(void (*print)(const char *fmt,...),struct ipcp_option_t*, uint8_t *ptr); struct ipaddr_option_t { struct ipcp_option_t opt; struct ppp_t *ppp; int started:1; }; static struct ipcp_option_handler_t ipaddr_opt_hnd = { .init = ipaddr_init, .send_conf_req = ipaddr_send_conf_req, .send_conf_nak = ipaddr_send_conf_nak, .recv_conf_req = ipaddr_recv_conf_req, .free = ipaddr_free, .print = ipaddr_print, }; static struct ipcp_option_t *ipaddr_init(struct ppp_ipcp_t *ipcp) { struct ipaddr_option_t *ipaddr_opt = _malloc(sizeof(*ipaddr_opt)); memset(ipaddr_opt, 0, sizeof(*ipaddr_opt)); ipaddr_opt->opt.id = CI_ADDR; ipaddr_opt->opt.len = 6; ipaddr_opt->ppp = ipcp->ppp; return &ipaddr_opt->opt; } static void ipaddr_free(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt) { struct ipaddr_option_t *ipaddr_opt = container_of(opt, typeof(*ipaddr_opt), opt); if (ipcp->ppp->ses.ipv4) { ipdb_put_ipv4(&ipcp->ppp->ses, ipcp->ppp->ses.ipv4); ipcp->ppp->ses.ipv4 = NULL; } _free(ipaddr_opt); } static int check_exists(struct ppp_t *self_ppp, in_addr_t addr) { struct ap_session *ses; int r = 0; pthread_rwlock_rdlock(&ses_lock); list_for_each_entry(ses, &ses_list, entry) { if (!ses->terminating && ses->ipv4 && ses->ipv4->peer_addr == addr && ses != &self_ppp->ses) { log_ppp_warn("ppp: requested IPv4 address already assigned to %s\n", ses->ifname); r = 1; break; } } pthread_rwlock_unlock(&ses_lock); return r; } static int alloc_ip(struct ppp_t *ppp) { ppp->ses.ipv4 = ipdb_get_ipv4(&ppp->ses); if (!ppp->ses.ipv4) { log_ppp_warn("ppp: no free IPv4 address\n"); return IPCP_OPT_CLOSE; } if (iprange_tunnel_check(ppp->ses.ipv4->peer_addr)) { log_ppp_warn("ppp:ipcp: to avoid kernel soft lockup requested IP cannot be assigned (%i.%i.%i.%i)\n", ppp->ses.ipv4->peer_addr&0xff, (ppp->ses.ipv4->peer_addr >> 8)&0xff, (ppp->ses.ipv4->peer_addr >> 16)&0xff, (ppp->ses.ipv4->peer_addr >> 24)&0xff); return IPCP_OPT_FAIL; } if (conf_check_exists && check_exists(ppp, ppp->ses.ipv4->peer_addr)) return IPCP_OPT_FAIL; return 0; } static int ipaddr_send_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr) { struct ipaddr_option_t *ipaddr_opt = container_of(opt, typeof(*ipaddr_opt), opt); struct ipcp_opt32_t *opt32 = (struct ipcp_opt32_t *)ptr; int r; if (!ipcp->ppp->ses.ipv4) { r = alloc_ip(ipcp->ppp); if (r) return r; } opt32->hdr.id = CI_ADDR; opt32->hdr.len = 6; opt32->val = ipcp->ppp->ses.ipv4->addr; return 6; } static int ipaddr_send_conf_nak(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr) { struct ipaddr_option_t *ipaddr_opt = container_of(opt, typeof(*ipaddr_opt), opt); struct ipcp_opt32_t *opt32 = (struct ipcp_opt32_t *)ptr; opt32->hdr.id = CI_ADDR; opt32->hdr.len = 6; opt32->val = ipcp->ppp->ses.ipv4->peer_addr; return 6; } static int ipaddr_recv_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr) { struct ipaddr_option_t *ipaddr_opt = container_of(opt, typeof(*ipaddr_opt), opt); struct ipcp_opt32_t *opt32 = (struct ipcp_opt32_t *)ptr; int r; if (!ipcp->ppp->ses.ipv4) { r = alloc_ip(ipcp->ppp); if (r) return r; } if (opt32->hdr.len != 6) return IPCP_OPT_REJ; if (ipcp->ppp->ses.ipv4->peer_addr == opt32->val) { ipcp->delay_ack = ccp_ipcp_started(ipcp->ppp); return IPCP_OPT_ACK; } return IPCP_OPT_NAK; } static void ipaddr_print(void (*print)(const char *fmt,...),struct ipcp_option_t *opt, uint8_t *ptr) { struct ipaddr_option_t *ipaddr_opt=container_of(opt,typeof(*ipaddr_opt),opt); struct ipcp_opt32_t *opt32=(struct ipcp_opt32_t*)ptr; struct in_addr in = { .s_addr = 0, }; if (ptr) in.s_addr = opt32->val; else if (ipaddr_opt->ppp->ses.ipv4) in.s_addr = ipaddr_opt->ppp->ses.ipv4->addr; print("",inet_ntoa(in)); } static void load_config(void) { const char *opt; opt = conf_get_opt("ppp", "check-ip"); if (opt && atoi(opt) > 0) conf_check_exists = 1; } static void ipaddr_opt_init() { ipcp_option_register(&ipaddr_opt_hnd); load_config(); triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config); } DEFINE_INIT(4, ipaddr_opt_init);