Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* -*- mode: c; c-basic-offset: 2 -*- */
- /*
- * Copyright (C) 2007-2013 David Bird (Coova Technologies) <support@coova.com>
- * Copyright (C) 2003-2005 Mondru AB.,
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- #include "chilli.h"
- #include "bstrlib.h"
- #ifdef ENABLE_MODULES
- #include "chilli_module.h"
- #endif
- struct tun_t *tun; /* TUN instance */
- struct ippool_t *ippool; /* Pool of IP addresses */
- struct radius_t *radius; /* Radius client instance */
- struct dhcp_t *dhcp = NULL; /* DHCP instance */
- struct redir_t *redir = NULL; /* Redir instance */
- #ifdef ENABLE_MULTIROUTE
- #include "rtmon.h"
- struct rtmon_t _rtmon;
- #endif
- static int connections=0;
- struct app_conn_t *firstfreeconn=0; /* First free in linked list */
- struct app_conn_t *lastfreeconn=0; /* Last free in linked list */
- struct app_conn_t *firstusedconn=0; /* First used in linked list */
- struct app_conn_t *lastusedconn=0; /* Last used in linked list */
- struct app_conn_t admin_session;
- struct timespec mainclock;
- time_t checktime;
- time_t rereadtime;
- static int *p_keep_going = 0;
- static int *p_reload_config = 0;
- /*static int do_timeouts = 1;*/
- static int do_interval = 0;
- #ifdef ENABLE_UAMANYIP
- /* some IPv4LL/APIPA(rfc 3927) specific stuff for uamanyip */
- struct in_addr ipv4ll_ip;
- struct in_addr ipv4ll_mask;
- #endif
- #ifdef ENABLE_SSDP
- #define SSDP_MCAST_ADDR ("239.255.255.250")
- #define SSDP_PORT 1900
- struct in_addr ssdp;
- #endif
- static int acct_req(acct_type type,
- struct app_conn_t *conn,
- uint8_t status_type);
- static pid_t chilli_pid = 0;
- #ifdef ENABLE_CHILLIPROXY
- static pid_t proxy_pid = 0;
- #endif
- #ifdef ENABLE_CHILLIRADSEC
- static pid_t radsec_pid = 0;
- #endif
- #ifdef ENABLE_CHILLIREDIR
- static pid_t redir_pid = 0;
- #endif
- typedef struct child {
- pid_t pid;
- uint8_t type;
- time_t started;
- char *name;
- struct child *next;
- } CHILD;
- static unsigned long child_count_tot = 0;
- static int child_count = 0;
- CHILD * children = 0;
- CHILD *child_create(uint8_t type, pid_t pid, char *name) {
- CHILD *node;
- if (!(node=malloc(sizeof(CHILD)))) return 0;
- node->started = mainclock_now();
- node->type = type;
- node->pid = pid;
- node->name = name;
- node->next = 0;
- return node;
- }
- CHILD *child_insert_head(CHILD *list, uint8_t type, pid_t pid, char *name) {
- CHILD *newnode = child_create(type, pid, name);
- if (!newnode) return 0;
- newnode->next = list;
- return newnode;
- }
- int child_add_pid(uint8_t type, pid_t pid, char *name) {
- if (!children) {
- /* Create the list head, the main process */
- children = child_create(CHILLI_PROC, getpid(), "[chilli]");
- if (!children) return -1;
- }
- children->next = child_insert_head(children->next, type, pid, name);
- if (!children->next) return -1;
- return 0;
- }
- int child_remove_pid(pid_t pid) {
- /* Will never be the head "children"-
- which is the main process pid */
- CHILD *list, *node;
- if (children) {
- list = children;
- while (list->next && list->next->pid != pid)
- list = list->next;
- if (list->next) {
- node = list->next;
- list->next = node->next;
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Freed child process %d [%s]", __FUNCTION__, __LINE__, node->pid, node->name);
- #endif
- free(node);
- return 0;
- }
- }
- return -1;
- }
- #if defined(ENABLE_CHILLIREDIR) || defined(ENABLE_CHILLIPROXY) || defined(ENABLE_CHILLIRADSEC)
- static pid_t launch_daemon(char *name, char *path) {
- pid_t cpid = getpid();
- pid_t p = chilli_fork(CHILLI_PROC_DAEMON, name);
- if (p < 0) {
- syslog(LOG_ERR, "%s: fork failed", strerror(errno));
- } else if (p == 0) {
- char *newargs[16];
- char file[128];
- int i=0;
- chilli_binconfig(file, sizeof(file), cpid);
- newargs[i++] = name;
- newargs[i++] = "-b";
- newargs[i++] = file;
- newargs[i++] = NULL;
- if (execv(path, newargs) != 0) {
- syslog(LOG_ERR, "%s: execl() did not return 0!", strerror(errno));
- exit(0);
- }
- } else {
- return p;
- }
- return 0;
- }
- #endif
- #ifdef ENABLE_CHILLIPROXY
- static void launch_chilliproxy() {
- proxy_pid = launch_daemon("[chilli_proxy]", SBINDIR "/chilli_proxy");
- }
- #endif
- #ifdef ENABLE_CHILLIREDIR
- static void launch_chilliredir() {
- redir_pid = launch_daemon("[chilli_redir]", SBINDIR "/chilli_redir");
- }
- #endif
- #ifdef ENABLE_CHILLIRADSEC
- static void launch_chilliradsec() {
- radsec_pid = launch_daemon("[chilli_radsec]", SBINDIR "/chilli_radsec");
- }
- #endif
- static int proc_status(char *name, pid_t pid) {
- char buffer[128];
- char * line = 0;
- size_t len = 0;
- int ret = 0;
- ssize_t read;
- FILE* fp;
- snprintf(buffer, sizeof(buffer), "/proc/%i/status", pid);
- fp = fopen(buffer, "r");
- if (!fp) return -1;
- while ((read = getline(&line, &len, fp)) != -1) {
- if (!memcmp(line, name, strlen(name))) {
- int i;
- if (sscanf(line+strlen(name)+1, "%d %s", &i, buffer) == 2) {
- ret = i;
- if (buffer[0] == 'm') ret *= 1000;
- else if (buffer[0] == 'g') ret *= 1000000;
- }
- }
- }
- if (line)
- free(line);
- fclose(fp);
- return ret;
- }
- static int proc_countfds(pid_t pid) {
- char buffer[128];
- int ret = 0;
- DIR *dir;
- struct dirent * d = 0;
- snprintf(buffer, sizeof(buffer), "/proc/%i/fd", pid);
- dir = opendir(buffer);
- if (!dir) return -1;
- while ((d = readdir(dir)))
- if (d->d_name[0] != '.')
- ret++;
- closedir(dir);
- return ret;
- }
- void child_print(bstring s) {
- time_t now = mainclock_now();
- CHILD *node = children;
- char line[256];
- snprintf(line, sizeof(line), "Children %d Max %d Total %ld\n",
- child_count, _options.childmax, child_count_tot);
- bcatcstr(s, line);
- while (node) {
- char *n = "";
- switch (node->type) {
- case CHILLI_PROC: n = "Main"; break;
- case CHILLI_PROC_DAEMON: n = "Daemon"; break;
- case CHILLI_PROC_REDIR: n = "Redirect"; break;
- case CHILLI_PROC_SCRIPT: n = "Script"; break;
- }
- snprintf(line, sizeof(line)-1,
- "PID %8d %-8s %-20s up %d [Vm Size: %d RSS: %d FDs: %d]\n",
- node->pid, n, node->name,
- (int)(now - node->started),
- proc_status("VmSize:", node->pid),
- proc_status("VmRSS:", node->pid),
- proc_countfds(node->pid));
- bcatcstr(s, line);
- node = node->next;
- }
- }
- void child_killall(int sig) {
- CHILD *node = children;
- while (node) {
- kill(node->pid, sig);
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): pid %d killed %d", __FUNCTION__, __LINE__, getpid(), node->pid);
- node = node->next;
- }
- }
- pid_t chilli_fork(uint8_t type, char *name) {
- pid_t pid;
- if (child_count == _options.childmax) {
- return -1;
- }
- pid = fork();
- if (pid > 0) {
- if (child_add_pid(type, pid, name) == 0) {
- ++child_count;
- ++child_count_tot;
- }
- }
- return pid;
- }
- static void _sigchld(int signum) {
- pid_t pid;
- int stat;
- while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) {
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): child %d terminated", __FUNCTION__, __LINE__, pid);
- #endif
- #ifdef ENABLE_CHILLIRADSEC
- if (!_options.debug && radsec_pid > 0 && radsec_pid == pid) {
- syslog(LOG_ERR, "Having to re-launch chilli_radsec... PID %d exited", pid);
- launch_chilliradsec();
- }
- #endif
- #ifdef ENABLE_CHILLIPROXY
- if (!_options.debug && proxy_pid > 0 && proxy_pid == pid) {
- syslog(LOG_ERR, "Having to re-launch chilli_proxy... PID %d exited", pid);
- launch_chilliproxy();
- }
- #endif
- #ifdef ENABLE_CHILLIREDIR
- if (!_options.debug && redir_pid > 0 && redir_pid == pid) {
- syslog(LOG_ERR, "Having to re-launch chilli_redir... PID %d exited", pid);
- launch_chilliredir();
- }
- #endif
- if (child_remove_pid(pid) == 0)
- child_count--;
- }
- }
- static void _sigterm(int signum) {
- syslog(LOG_DEBUG, "%s(%d): SIGTERM: shutdown", __FUNCTION__, __LINE__);
- if (p_keep_going)
- *p_keep_going = 0;
- }
- static void _sigvoid(int signum) {
- #if(_debug_)
- syslog(LOG_DEBUG, "%s(%d): received %d signal", __FUNCTION__, __LINE__, signum);
- #endif
- }
- static void _sigusr1(int signum) {
- syslog(LOG_DEBUG, "%s(%d): SIGUSR1: reloading configuration", __FUNCTION__, __LINE__);
- if (p_reload_config)
- *p_reload_config = 1;
- #ifdef ENABLE_CHILLIREDIR
- if (redir_pid)
- kill(redir_pid, SIGUSR1);
- #endif
- #ifdef ENABLE_CHILLIPROXY
- if (proxy_pid)
- kill(proxy_pid, SIGUSR1);
- #endif
- #ifdef ENABLE_CHILLIRADSEC
- if (radsec_pid)
- kill(radsec_pid, SIGUSR1);
- #endif
- }
- static void _sighup(int signum) {
- syslog(LOG_DEBUG, "%s(%d): SIGHUP: rereading configuration", __FUNCTION__, __LINE__);
- do_interval = 1;
- }
- int chilli_handle_signal(void *ctx, int fd) {
- int signo = selfpipe_read();
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): caught %d via selfpipe", __FUNCTION__, __LINE__, signo);
- #endif
- switch (signo) {
- case SIGCHLD: _sigchld(signo); break;
- case SIGPIPE: _sigvoid(signo); break;
- case SIGHUP: _sighup(signo); break;
- case SIGUSR1: _sigusr1(signo); break;
- case SIGTERM:
- case SIGINT: _sigterm(signo); break;
- default: return signo;
- }
- return 0;
- }
- void chilli_signals(int *with_term, int *with_hup) {
- selfpipe_trap(SIGCHLD);
- selfpipe_trap(SIGPIPE);
- if (with_hup) {
- p_reload_config = with_hup;
- selfpipe_trap(SIGHUP);
- selfpipe_trap(SIGUSR1);
- }
- if (with_term) {
- p_keep_going = with_term;
- selfpipe_trap(SIGTERM);
- selfpipe_trap(SIGINT);
- }
- }
- int chilli_binconfig(char *file, size_t flen, pid_t pid) {
- if (pid == 0) {
- char * bc = _options.binconfig;
- if (bc) {
- snprintf(file, flen, "%s", bc);
- return 0;
- } else {
- pid = chilli_pid;
- if (pid == 0)
- pid = getpid();
- }
- }
- snprintf(file, flen, DEFSTATEDIR "/chilli.%d.cfg.bin", pid);
- return 0;
- }
- int chilli_appconn_run(int (*cb)(struct app_conn_t *, void *), void *d) {
- struct app_conn_t *appconn = firstusedconn;
- while (appconn) {
- if (cb(appconn, d))
- return 1;
- appconn = appconn->next;
- }
- return 0;
- }
- #ifdef HAVE_LIBRT
- static struct timespec startup_real;
- static struct timespec startup_mono;
- #endif
- static time_t start_tick = 0;
- time_t mainclock_towall(time_t t) {
- #ifdef HAVE_LIBRT
- if (startup_real.tv_sec)
- return startup_real.tv_sec + (t - start_tick);
- #endif
- return mainclock.tv_sec;
- }
- time_t mainclock_wall() {
- return mainclock_towall(mainclock.tv_sec);
- }
- time_t mainclock_tick() {
- #ifdef HAVE_LIBRT
- struct timespec ts;
- #if defined(CLOCK_MONOTONIC)
- clockid_t cid = CLOCK_MONOTONIC;
- #else
- clockid_t cid = CLOCK_REALTIME;
- #endif
- int res = clock_gettime(cid, &ts);
- if (res == -1 && errno == EINVAL) {
- cid = CLOCK_REALTIME;
- res = clock_gettime(cid, &ts);
- }
- if (res == -1) {
- syslog(LOG_ERR, "%s: clock_gettime()", strerror(errno));
- /* drop through to old time() */
- } else {
- mainclock.tv_sec = ts.tv_sec;
- mainclock.tv_nsec = ts.tv_nsec;
- return mainclock.tv_sec;
- }
- #endif
- if (time(&mainclock.tv_sec) == (time_t)-1) {
- syslog(LOG_ERR, "%s: time()", strerror(errno));
- }
- return mainclock.tv_sec;
- }
- time_t mainclock_now() {
- return mainclock.tv_sec;
- }
- time_t mainclock_rt() {
- time_t rt = 0;
- #ifdef HAVE_LIBRT
- struct timespec ts;
- clockid_t cid = CLOCK_REALTIME;
- if (clock_gettime(cid, &ts) < 0) {
- syslog(LOG_ERR, "%s: clock_gettime()", strerror(errno));
- /* drop through to old time() */
- } else {
- rt = ts.tv_sec;
- return rt;
- }
- #endif
- if (time(&rt) == (time_t)-1) {
- syslog(LOG_ERR, "%s: time()", strerror(errno));
- }
- return rt;
- }
- int mainclock_rtdiff(time_t past) {
- time_t rt = mainclock_rt();
- return (int) difftime(rt, past);
- }
- int mainclock_diff(time_t past) {
- return (int) (mainclock.tv_sec - past);
- }
- uint32_t mainclock_diffu(time_t past) {
- int i = mainclock_diff(past);
- if (i > 0) return (uint32_t) i;
- return 0;
- }
- void mainclock_tsdiff(struct timespec *out,
- struct timespec *start,
- struct timespec *end) {
- if ((end->tv_nsec - start->tv_nsec) < 0) {
- out->tv_sec = end->tv_sec - start->tv_sec-1;
- out->tv_nsec = 1000000000 + end->tv_nsec - start->tv_nsec;
- } else {
- out->tv_sec = end->tv_sec - start->tv_sec;
- out->tv_nsec = end->tv_nsec - start->tv_nsec;
- }
- }
- double mainclock_diffd(struct timespec * past) {
- double d = 0;
- struct timespec tsd;
- mainclock_tsdiff(&tsd, past, &mainclock);
- d = tsd.tv_nsec;
- d /= 1000000000.0;
- d += tsd.tv_sec;
- return d;
- }
- uint8_t* chilli_called_station(struct session_state *state) {
- #ifdef ENABLE_LOCATION
- if (_options.location_copy_called && state->redir.calledlen) {
- return state->redir.called;
- }
- #endif
- return dhcp_nexthop(dhcp);
- }
- static void set_sessionid(struct app_conn_t *appconn, char full) {
- appconn->rt = (int) mainclock_rt();
- snprintf(appconn->s_state.sessionid,
- sizeof(appconn->s_state.sessionid),
- "%.8lx%.8x", appconn->rt, appconn->unit);
- appconn->s_state.redir.classlen = 0;
- appconn->s_state.redir.statelen = 0;
- #ifdef ENABLE_SESSIONID
- if (full) {
- uint8_t * his = appconn->hismac;
- uint8_t * called = dhcp_nexthop(dhcp);
- snprintf(appconn->s_state.chilli_sessionid,
- sizeof(appconn->s_state.chilli_sessionid),
- "SES-"
- "%.2X%.2X%.2X%.2X%.2X%.2X-"
- "%.2X%.2X%.2X%.2X%.2X%.2X-"
- "%.8lx%.8x",
- MAC_ARG(his), MAC_ARG(called),
- appconn->rt, appconn->unit);
- }
- #endif
- }
- /* Used to write process ID to file. Assume someone else will delete */
- static void log_pid(char *pidfile) {
- FILE *file;
- mode_t oldmask;
- oldmask = umask(022);
- file = fopen(pidfile, "w");
- umask(oldmask);
- if(!file) return;
- fprintf(file, "%d\n", getpid());
- fclose(file);
- }
- #ifdef ENABLE_LEAKYBUCKET
- static inline void leaky_bucket_init(struct app_conn_t *conn) {
- if (_options.bwbucketupsize) {
- conn->s_state.bucketupsize = _options.bwbucketupsize;
- } else {
- #ifdef BUCKET_SIZE
- conn->s_state.bucketupsize = BUCKET_SIZE;
- #else
- conn->s_state.bucketupsize =
- conn->s_params.bandwidthmaxup / 8 * BUCKET_TIME;
- if (conn->s_state.bucketupsize < BUCKET_SIZE_MIN)
- conn->s_state.bucketupsize = BUCKET_SIZE_MIN;
- #endif
- }
- if (_options.bwbucketdnsize) {
- conn->s_state.bucketdownsize = _options.bwbucketdnsize;
- } else {
- #ifdef BUCKET_SIZE
- conn->s_state.bucketdownsize = BUCKET_SIZE;
- #else
- conn->s_state.bucketdownsize =
- conn->s_params.bandwidthmaxdown / 8 * BUCKET_TIME;
- if (conn->s_state.bucketdownsize < BUCKET_SIZE_MIN)
- conn->s_state.bucketdownsize = BUCKET_SIZE_MIN;
- #endif
- }
- if (_options.bwbucketminsize > 0) {
- if (conn->s_state.bucketupsize < _options.bwbucketminsize)
- conn->s_state.bucketupsize = _options.bwbucketminsize;
- if (conn->s_state.bucketdownsize < _options.bwbucketminsize)
- conn->s_state.bucketdownsize = _options.bwbucketminsize;
- }
- }
- /* Perform leaky bucket on up- and downlink traffic */
- static inline int
- leaky_bucket(struct app_conn_t *conn,
- uint64_t octetsup, uint64_t octetsdown) {
- int result = 0;
- uint64_t upbytes=0, dnbytes=0;
- long double timediff;
- timediff = mainclock_diffd(&conn->s_state.last_bw_time);
- if (conn->s_params.bandwidthmaxup) {
- upbytes = (uint64_t) ((timediff * conn->s_params.bandwidthmaxup) / 8);
- if (!conn->s_state.bucketupsize) {
- leaky_bucket_init(conn);
- }
- if (conn->s_state.bucketup > upbytes) {
- conn->s_state.bucketup -= upbytes;
- }
- else {
- conn->s_state.bucketup = 0;
- }
- if ((conn->s_state.bucketup + octetsup) >
- conn->s_state.bucketupsize) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Leaky bucket dropping upload overflow from "MAC_FMT, __FUNCTION__, __LINE__,
- MAC_ARG(conn->hismac));
- result = -1;
- }
- else {
- conn->s_state.bucketup += octetsup;
- }
- }
- if (conn->s_params.bandwidthmaxdown) {
- dnbytes = (uint64_t) ((timediff * conn->s_params.bandwidthmaxdown) / 8);
- if (!conn->s_state.bucketdownsize) {
- leaky_bucket_init(conn);
- }
- if (conn->s_state.bucketdown > dnbytes) {
- conn->s_state.bucketdown -= dnbytes;
- }
- else {
- conn->s_state.bucketdown = 0;
- }
- if ((conn->s_state.bucketdown + octetsdown) >
- conn->s_state.bucketdownsize) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Leaky bucket dropping download overflow to "MAC_FMT, __FUNCTION__, __LINE__,
- MAC_ARG(conn->hismac));
- result = -1;
- }
- else {
- conn->s_state.bucketdown += octetsdown;
- }
- }
- #if(0)
- if (_options.debug &&
- (conn->s_params.bandwidthmaxup || conn->s_params.bandwidthmaxdown))
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Leaky bucket: bucketup: %lld/%lld, " __FUNCTION__, __LINE__,
- "bucketdown: %lld/%lld, up: %lld/(%lld), down: %lld/(%lld)",
- conn->s_state.bucketup, conn->s_state.bucketupsize,
- conn->s_state.bucketdown, conn->s_state.bucketdownsize,
- octetsup, upbytes, octetsdown, dnbytes);
- #endif
- conn->s_state.last_bw_time.tv_sec = mainclock.tv_sec;
- conn->s_state.last_bw_time.tv_nsec = mainclock.tv_nsec;
- return result;
- }
- #endif
- void set_env(char *name, char type, void *value, int len) {
- char *v=0;
- char s[1024];
- memset(s,0,sizeof(s));
- switch(type) {
- case VAL_IN_ADDR:
- strlcpy(s, inet_ntoa(*(struct in_addr *)value), sizeof(s));
- v = s;
- break;
- case VAL_MAC_ADDR:
- {
- uint8_t * mac = (uint8_t*)value;
- snprintf(s, sizeof(s), MAC_FMT, MAC_ARG(mac));
- v = s;
- }
- break;
- case VAL_ULONG:
- snprintf(s, sizeof(s), "%ld", (long int)*(uint32_t *)value);
- v = s;
- break;
- case VAL_ULONG64:
- snprintf(s, sizeof(s), "%ld", (long int)*(uint64_t *)value);
- v = s;
- break;
- case VAL_USHORT:
- snprintf(s, sizeof(s), "%d", (int)(*(uint16_t *)value));
- v = s;
- break;
- case VAL_STRING:
- if (len > 0) {
- if (len > sizeof(s) - 1)
- len = sizeof(s) - 1;
- memcpy(s, (char*)value, len);
- s[len]=0;
- v = s;
- } else {
- v = (char*)value;
- }
- break;
- }
- if (name != NULL && v != NULL) {
- if (setenv(name, v, 1) != 0) {
- syslog(LOG_ERR, "%s: setenv(%s, %s, 1) did not return 0!", strerror(errno), name, v);
- }
- }
- }
- int runscript(struct app_conn_t *appconn, char* script,
- char *loc, char *oloc) {
- int status;
- uint32_t sessiontime;
- if ((status = chilli_fork(CHILLI_PROC_SCRIPT, script)) < 0) {
- syslog(LOG_ERR, "%s: forking %s", strerror(errno), script);
- return 0;
- }
- if (status > 0) { /* Parent */
- return 0;
- }
- #ifdef ENABLE_LAYER3
- if (_options.layer3)
- set_env("LAYER3", VAL_STRING, "1", 0);
- #endif
- set_env("DEV", VAL_STRING, tun(tun, 0).devname, 0);
- set_env("NET", VAL_IN_ADDR, &appconn->net, 0);
- set_env("MASK", VAL_IN_ADDR, &appconn->mask, 0);
- set_env("ADDR", VAL_IN_ADDR, &appconn->ourip, 0);
- set_env("USER_NAME", VAL_STRING, appconn->s_state.redir.username, 0);
- set_env("NAS_IP_ADDRESS", VAL_IN_ADDR,&_options.radiuslisten, 0);
- set_env("SERVICE_TYPE", VAL_STRING, "1", 0);
- set_env("FRAMED_IP_ADDRESS", VAL_IN_ADDR, &appconn->hisip, 0);
- set_env("FILTER_ID", VAL_STRING, appconn->s_params.filteridbuf, 0);
- set_env("STATE", VAL_STRING, appconn->s_state.redir.statebuf, appconn->s_state.redir.statelen);
- set_env("CLASS", VAL_STRING, appconn->s_state.redir.classbuf, appconn->s_state.redir.classlen);
- set_env("CUI", VAL_STRING, appconn->s_state.redir.cuibuf, appconn->s_state.redir.cuilen);
- set_env("SESSION_TIMEOUT", VAL_ULONG64, &appconn->s_params.sessiontimeout, 0);
- set_env("IDLE_TIMEOUT", VAL_ULONG, &appconn->s_params.idletimeout, 0);
- set_env("CALLING_STATION_ID", VAL_MAC_ADDR, appconn->hismac, 0);
- set_env("CALLED_STATION_ID", VAL_MAC_ADDR, chilli_called_station(&appconn->s_state), 0);
- set_env("NAS_ID", VAL_STRING, _options.radiusnasid, 0);
- set_env("NAS_PORT_TYPE", VAL_STRING, "19", 0);
- set_env("ACCT_SESSION_ID", VAL_STRING, appconn->s_state.sessionid, 0);
- set_env("ACCT_INTERIM_INTERVAL", VAL_USHORT, &appconn->s_params.interim_interval, 0);
- set_env("WISPR_LOCATION_ID", VAL_STRING, _options.radiuslocationid, 0);
- set_env("WISPR_LOCATION_NAME", VAL_STRING, _options.radiuslocationname, 0);
- set_env("WISPR_BANDWIDTH_MAX_UP", VAL_ULONG, &appconn->s_params.bandwidthmaxup, 0);
- set_env("WISPR_BANDWIDTH_MAX_DOWN", VAL_ULONG, &appconn->s_params.bandwidthmaxdown, 0);
- /*set_env("WISPR-SESSION_TERMINATE_TIME", VAL_USHORT, &appconn->sessionterminatetime, 0);*/
- set_env("COOVACHILLI_MAX_INPUT_OCTETS", VAL_ULONG64, &appconn->s_params.maxinputoctets, 0);
- set_env("COOVACHILLI_MAX_OUTPUT_OCTETS", VAL_ULONG64, &appconn->s_params.maxoutputoctets, 0);
- set_env("COOVACHILLI_MAX_TOTAL_OCTETS", VAL_ULONG64, &appconn->s_params.maxtotaloctets, 0);
- set_env("INPUT_OCTETS", VAL_ULONG64, &appconn->s_state.input_octets, 0);
- set_env("OUTPUT_OCTETS", VAL_ULONG64, &appconn->s_state.output_octets, 0);
- set_env("INPUT_PACKETS", VAL_ULONG64, &appconn->s_state.input_packets, 0);
- set_env("OUTPUT_PACKETS", VAL_ULONG64, &appconn->s_state.output_packets, 0);
- sessiontime = mainclock_diffu(appconn->s_state.start_time);
- set_env("SESSION_TIME", VAL_ULONG, &sessiontime, 0);
- sessiontime = mainclock_diffu(appconn->s_state.last_up_time);
- set_env("IDLE_TIME", VAL_ULONG, &sessiontime, 0);
- if (loc) {
- set_env("LOCATION", VAL_STRING, loc, 0);
- }
- if (oloc) {
- set_env("OLD_LOCATION", VAL_STRING, oloc, 0);
- }
- if (appconn->s_state.terminate_cause)
- set_env("TERMINATE_CAUSE", VAL_ULONG,
- &appconn->s_state.terminate_cause, 0);
- if (execl(
- #ifdef ENABLE_CHILLISCRIPT
- SBINDIR "/chilli_script", SBINDIR "/chilli_script", _options.binconfig,
- #else
- script,
- #endif
- script, (char *) 0) != 0) {
- syslog(LOG_ERR, "%s: exec %s failed", strerror(errno), script);
- }
- exit(0);
- }
- /***********************************************************
- *
- * Functions handling uplink protocol authentication.
- * Called in response to radius access request response.
- *
- ***********************************************************/
- static int newip(struct ippoolm_t **ipm, struct in_addr *hisip, uint8_t *hismac) {
- #ifdef ENABLE_UAMANYIP
- struct in_addr tmpip;
- if (_options.autostatip && hismac) {
- if (!hisip) hisip = &tmpip;
- hisip->s_addr = htonl((_options.autostatip % 255) * 0x1000000 +
- hismac[3] * 0x10000 +
- hismac[4] * 0x100 +
- hismac[5]);
- }
- #endif
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): newip %s", __FUNCTION__, __LINE__, inet_ntoa(*hisip));
- if (ippool_newip(ippool, ipm, hisip, 1)) {
- if (ippool_newip(ippool, ipm, hisip, 0)) {
- syslog(LOG_ERR, "Failed to allocate either static or dynamic IP address");
- return -1;
- }
- }
- return 0;
- }
- /*
- * A few functions to manage connections
- */
- static int initconn() {
- checktime = rereadtime = mainclock.tv_sec;
- return 0;
- }
- int chilli_new_conn(struct app_conn_t **conn) {
- int n;
- if (!firstfreeconn) {
- if (connections == _options.max_clients) {
- syslog(LOG_ERR, "reached max connections %d!", _options.max_clients);
- return -1;
- }
- n = ++connections;
- if (!(*conn = calloc(1, sizeof(struct app_conn_t)))) {
- syslog(LOG_ERR, "Out of memory!");
- connections--;
- return -1;
- }
- } else {
- *conn = firstfreeconn;
- n = (*conn)->unit;
- /* Remove from link of free */
- if (firstfreeconn->next) {
- firstfreeconn->next->prev = NULL;
- firstfreeconn = firstfreeconn->next;
- }
- else { /* Took the last one */
- firstfreeconn = NULL;
- lastfreeconn = NULL;
- }
- /* Initialise structures */
- memset(*conn, 0, sizeof(struct app_conn_t));
- }
- /* Initalise connection with default options */
- session_param_defaults(&(*conn)->s_params);
- /* Insert into link of used */
- if (firstusedconn) {
- firstusedconn->prev = *conn;
- (*conn)->next = firstusedconn;
- }
- else { /* First insert */
- lastusedconn = *conn;
- }
- firstusedconn = *conn;
- (*conn)->inuse = 1;
- (*conn)->unit = n;
- return 0; /* Success */
- }
- int static freeconn(struct app_conn_t *conn) {
- int n = conn->unit;
- #ifdef ENABLE_GARDENACCOUNTING
- if (_options.uamgardendata) {
- acct_req(ACCT_GARDEN, conn, RADIUS_STATUS_TYPE_STOP);
- }
- #endif
- #ifdef WITH_PATRICIA
- if (conn->ptree)
- patricia_destroy (conn->ptree, free);
- #endif
- #if defined(ENABLE_LOCATION) && defined(HAVE_AVL)
- /*remove from location list (if we have a location/are in list) !!??*/
- if (conn->loc_search_node!=NULL) location_close_conn(conn,1);
- #endif
- /* Remove from link of used */
- if ((conn->next) && (conn->prev)) {
- conn->next->prev = conn->prev;
- conn->prev->next = conn->next;
- }
- else if (conn->next) { /* && prev == 0 */
- conn->next->prev = NULL;
- firstusedconn = conn->next;
- }
- else if (conn->prev) { /* && next == 0 */
- conn->prev->next = NULL;
- lastusedconn = conn->prev;
- }
- else { /* if ((next == 0) && (prev == 0)) */
- firstusedconn = NULL;
- lastusedconn = NULL;
- }
- /* Initialise structures */
- memset(conn, 0, sizeof(struct app_conn_t));
- conn->unit = n;
- /* Insert into link of free */
- if (firstfreeconn) {
- firstfreeconn->prev = conn;
- }
- else { /* First insert */
- lastfreeconn = conn;
- }
- conn->next = firstfreeconn;
- firstfreeconn = conn;
- return 0;
- }
- int chilli_getconn(struct app_conn_t **conn, uint32_t ip,
- uint32_t nasip, uint32_t nasport) {
- struct app_conn_t *appconn = firstusedconn;
- while (appconn) {
- if (!appconn->inuse) {
- syslog(LOG_ERR, "Connection with inuse == 0!");
- }
- if (ip && appconn->hisip.s_addr == ip) {
- *conn = appconn;
- return 0;
- }
- if (nasip && nasport &&
- (appconn->nasip == nasip) && (appconn->nasport == nasport)) {
- *conn = appconn;
- return 0;
- }
- appconn = appconn->next;
- }
- return -1; /* Not found */
- }
- static int dnprot_terminate(struct app_conn_t *appconn) {
- appconn->s_state.authenticated = 0;
- #ifdef ENABLE_SESSIONSTATE
- appconn->s_state.session_state = 0;
- #endif
- if (appconn->s_params.url[0] &&
- appconn->s_params.flags & UAM_CLEAR_URL) {
- appconn->s_params.flags &= ~UAM_CLEAR_URL;
- appconn->s_params.url[0] = 0;
- }
- #ifdef ENABLE_LEAKYBUCKET
- appconn->s_state.bucketup = 0;
- appconn->s_state.bucketdown = 0;
- appconn->s_state.bucketupsize = 0;
- appconn->s_state.bucketdownsize = 0;
- #endif
- #ifdef HAVE_NETFILTER_COOVA
- if (_options.kname) {
- kmod_coova_update(appconn);
- }
- #endif
- #ifdef ENABLE_LAYER3
- if (!_options.layer3)
- #endif
- switch (appconn->dnprot) {
- case DNPROT_WPA:
- #ifdef ENABLE_EAPOL
- case DNPROT_EAPOL:
- #endif
- if (appconn->dnlink)
- ((struct dhcp_conn_t*) appconn->dnlink)->authstate = DHCP_AUTH_NONE;
- break;
- case DNPROT_MAC:
- case DNPROT_UAM:
- case DNPROT_DHCP_NONE:
- case DNPROT_NULL:
- if (appconn->dnlink)
- ((struct dhcp_conn_t*) appconn->dnlink)->authstate = DHCP_AUTH_DNAT;
- break;
- #ifdef ENABLE_LAYER3
- case DNPROT_LAYER3:
- break;
- #endif
- default:
- syslog(LOG_ERR, "Unknown downlink protocol");
- break;
- }
- return 0;
- }
- /* Check for:
- * - Session-Timeout
- * - Idle-Timeout
- * - Interim-Interim accounting
- * - Reread configuration file and DNS entries
- */
- void session_interval(struct app_conn_t *conn) {
- uint32_t sessiontime;
- uint32_t idletime;
- uint32_t interimtime;
- sessiontime = mainclock_diffu(conn->s_state.start_time);
- idletime = mainclock_diffu(conn->s_state.last_up_time);
- interimtime = mainclock_diffu(conn->s_state.interim_time);
- if (conn->s_state.authenticated == 1) {
- if ((conn->s_params.sessiontimeout) &&
- (sessiontime > conn->s_params.sessiontimeout)) {
- #ifdef ENABLE_SESSIONSTATE
- conn->s_state.session_state =
- RADIUS_VALUE_COOVACHILLI_SESSION_TIMEOUT_REACHED;
- #endif
- terminate_appconn(conn, RADIUS_TERMINATE_CAUSE_SESSION_TIMEOUT);
- }
- else if ((conn->s_params.sessionterminatetime) &&
- (mainclock_rtdiff(conn->s_params.sessionterminatetime) > 0)) {
- #ifdef ENABLE_SESSIONSTATE
- conn->s_state.session_state =
- RADIUS_VALUE_COOVACHILLI_SESSION_LOGOUT_TIME_REACHED;
- #endif
- terminate_appconn(conn, RADIUS_TERMINATE_CAUSE_SESSION_TIMEOUT);
- }
- else if ((conn->s_params.idletimeout) &&
- (idletime > conn->s_params.idletimeout)) {
- #ifdef ENABLE_SESSIONSTATE
- conn->s_state.session_state =
- RADIUS_VALUE_COOVACHILLI_SESSION_IDLE_TIMEOUT_REACHED;
- #endif
- terminate_appconn(conn, RADIUS_TERMINATE_CAUSE_IDLE_TIMEOUT);
- }
- else if ((conn->s_params.maxinputoctets) &&
- (conn->s_state.input_octets > conn->s_params.maxinputoctets)) {
- #ifdef ENABLE_SESSIONSTATE
- conn->s_state.session_state =
- RADIUS_VALUE_COOVACHILLI_SESSION_IN_DATALIMIT_REACHED;
- #endif
- terminate_appconn(conn, RADIUS_TERMINATE_CAUSE_SESSION_TIMEOUT);
- }
- else if ((conn->s_params.maxoutputoctets) &&
- (conn->s_state.output_octets > conn->s_params.maxoutputoctets)) {
- #ifdef ENABLE_SESSIONSTATE
- conn->s_state.session_state =
- RADIUS_VALUE_COOVACHILLI_SESSION_OUT_DATALIMIT_REACHED;
- #endif
- terminate_appconn(conn, RADIUS_TERMINATE_CAUSE_SESSION_TIMEOUT);
- }
- else if ((conn->s_params.maxtotaloctets) &&
- ((conn->s_state.input_octets + conn->s_state.output_octets) >
- conn->s_params.maxtotaloctets)) {
- #ifdef ENABLE_SESSIONSTATE
- conn->s_state.session_state =
- RADIUS_VALUE_COOVACHILLI_SESSION_TOTAL_DATALIMIT_REACHED;
- #endif
- terminate_appconn(conn, RADIUS_TERMINATE_CAUSE_SESSION_TIMEOUT);
- }
- else if ((conn->s_params.interim_interval) &&
- (interimtime >= conn->s_params.interim_interval)) {
- #ifdef ENABLE_MODULES
- { int i;
- for (i=0; i < MAX_MODULES; i++) {
- if (!_options.modules[i].name[0]) break;
- if (_options.modules[i].ctx) {
- struct chilli_module *m =
- (struct chilli_module *)_options.modules[i].ctx;
- if (m->session_update)
- m->session_update(conn);
- }
- }
- }
- #endif
- acct_req(ACCT_USER, conn, RADIUS_STATUS_TYPE_INTERIM_UPDATE);
- }
- }
- #ifdef ENABLE_GARDENACCOUNTING
- interimtime = mainclock_diffu(conn->s_state.garden_interim_time);
- if (_options.uamgardendata &&
- _options.definteriminterval &&
- interimtime >= _options.definteriminterval) {
- acct_req(ACCT_GARDEN, conn, RADIUS_STATUS_TYPE_INTERIM_UPDATE);
- }
- #endif
- }
- static int checkconn() {
- struct app_conn_t *conn;
- struct dhcp_conn_t* dhcpconn;
- uint32_t checkdiff;
- uint32_t rereaddiff;
- #ifdef HAVE_NETFILTER_COOVA
- if (_options.kname) {
- kmod_coova_sync();
- }
- #endif
- checkdiff = mainclock_diffu(checktime);
- if (checkdiff < CHECK_INTERVAL)
- return 0;
- checktime = mainclock.tv_sec;
- if (admin_session.s_state.authenticated) {
- session_interval(&admin_session);
- }
- for (conn = firstusedconn; conn; conn=conn->next) {
- if (conn->inuse != 0) {
- if (
- #ifdef ENABLE_LAYER3
- !_options.layer3 &&
- #endif
- !(dhcpconn = (struct dhcp_conn_t *)conn->dnlink)) {
- syslog(LOG_WARNING, "No downlink protocol");
- continue;
- }
- session_interval(conn);
- }
- }
- /* Reread configuration file and recheck DNS */
- if (_options.interval) {
- rereaddiff = mainclock_diffu(rereadtime);
- if (rereaddiff >= _options.interval) {
- rereadtime = mainclock.tv_sec;
- do_interval = 1;
- }
- }
- return 0;
- }
- void chilli_freeconn() {
- struct app_conn_t *conn, *c;
- struct dhcp_conn_t *d = NULL;
- for (conn = firstusedconn; conn; ) {
- c = conn;
- conn = conn->next;
- d = (struct dhcp_conn_t *)c->dnlink;
- if (d) d->peer = NULL;
- free(c);
- }
- for (conn = firstfreeconn; conn; ) {
- c = conn;
- conn = conn->next;
- free(c);
- }
- }
- /* Kill all connections and send Radius Acct Stop */
- int static killconn() {
- struct app_conn_t *conn;
- for (conn = firstusedconn; conn; conn = conn->next) {
- if ((conn->inuse != 0) && (conn->s_state.authenticated == 1)) {
- terminate_appconn(conn, RADIUS_TERMINATE_CAUSE_NAS_REBOOT);
- }
- }
- if (admin_session.s_state.authenticated) {
- admin_session.s_state.terminate_cause = RADIUS_TERMINATE_CAUSE_NAS_REBOOT;
- acct_req(ACCT_USER, &admin_session, RADIUS_STATUS_TYPE_STOP);
- }
- #ifdef ENABLE_ACCOUNTING_ONOFF
- acct_req(ACCT_USER, &admin_session, RADIUS_STATUS_TYPE_ACCOUNTING_OFF);
- #endif
- chilli_freeconn();
- return 0;
- }
- /* Compare a MAC address to the addresses given in the macallowed option */
- int static maccmp(unsigned char *mac) {
- int i;
- for (i=0; i<_options.macoklen; i++)
- if (!memcmp(mac, _options.macok[i], PKT_ETH_ALEN))
- return 0;
- return -1;
- }
- int chilli_req_attrs(struct radius_t *radius,
- struct radius_packet_t *pack,
- acct_type type,
- uint32_t service_type,
- uint8_t status_type,
- uint32_t port,
- uint8_t *hismac,
- struct in_addr *hisip,
- struct session_state *state) {
- char *sessionid = state->sessionid;
- char mac[MACSTRLEN+1];
- switch(pack->code) {
- case RADIUS_CODE_ACCESS_REQUEST:
- if (_options.radiusoriginalurl) {
- if (state->redir.userurl[0])
- radius_addattr(radius, pack, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_ORIGINALURL,
- 0, (uint8_t *) state->redir.userurl,
- strlen(state->redir.userurl));
- #ifdef ENABLE_USERAGENT
- if (state->redir.useragent[0])
- radius_addattr(radius, pack, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_USER_AGENT,
- 0, (uint8_t *) state->redir.useragent,
- strlen(state->redir.useragent));
- #endif
- #ifdef ENABLE_ACCEPTLANGUAGE
- if (state->redir.acceptlanguage[0])
- radius_addattr(radius, pack, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_ACCEPT_LANGUAGE,
- 0, (uint8_t *) state->redir.acceptlanguage,
- strlen(state->redir.acceptlanguage));
- #endif
- }
- break;
- default:
- break;
- }
- if (service_type)
- radius_addattr(radius, pack, RADIUS_ATTR_SERVICE_TYPE, 0, 0,
- service_type, NULL, 0);
- if (status_type)
- radius_addattr(radius, pack, RADIUS_ATTR_ACCT_STATUS_TYPE, 0, 0,
- status_type, NULL, 0);
- #ifdef ENABLE_IEEE8021Q
- if (_options.ieee8021q && state->tag8021q) {
- radius_addattr(radius, pack, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI, RADIUS_ATTR_COOVACHILLI_VLAN_ID,
- (uint32_t)ntohs(state->tag8021q & PKT_8021Q_MASK_VID), 0, 0);
- }
- #endif
- #ifdef ENABLE_GARDENACCOUNTING
- switch(type) {
- case ACCT_GARDEN:
- sessionid = state->garden_sessionid;
- break;
- case ACCT_USER:
- default:
- break;
- }
- #endif
- if (*sessionid) {
- radius_addattr(radius, pack, RADIUS_ATTR_ACCT_SESSION_ID, 0, 0, 0,
- (uint8_t *)sessionid, strlen(sessionid));
- }
- #ifdef ENABLE_SESSIONID
- if (state->chilli_sessionid[0]) {
- radius_addattr(radius, pack, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_SESSION_ID,
- 0, (uint8_t *) state->chilli_sessionid,
- strlen(state->chilli_sessionid));
- }
- #endif
- #ifdef ENABLE_APSESSIONID
- if (state->ap_sessionid[0]) {
- radius_addattr(radius, pack, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_AP_SESSION_ID,
- 0, (uint8_t *) state->ap_sessionid,
- strlen(state->ap_sessionid));
- }
- #endif
- switch(type) {
- #ifdef ENABLE_GARDENACCOUNTING
- case ACCT_GARDEN:
- break;
- #endif
- case ACCT_USER:
- if (state->redir.classlen) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): RADIUS Request + Class(%zu)", __FUNCTION__, __LINE__, state->redir.classlen);
- radius_addattr(radius, pack,
- RADIUS_ATTR_CLASS, 0, 0, 0,
- state->redir.classbuf,
- state->redir.classlen);
- }
- if (state->redir.cuilen > 1) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): RADIUS Request + CUI(%zu)", __FUNCTION__, __LINE__, state->redir.cuilen);
- radius_addattr(radius, pack,
- RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 0, 0, 0,
- state->redir.cuibuf,
- state->redir.cuilen);
- }
- if (state->redir.statelen) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): RADIUS Request + State(%d)", __FUNCTION__, __LINE__, state->redir.statelen);
- radius_addattr(radius, pack,
- RADIUS_ATTR_STATE, 0, 0, 0,
- state->redir.statebuf,
- state->redir.statelen);
- }
- break;
- }
- if (hisip && hisip->s_addr) {
- radius_addattr(radius, pack, RADIUS_ATTR_FRAMED_IP_ADDRESS, 0, 0,
- ntohl(hisip->s_addr), NULL, 0);
- }
- radius_addattr(radius, pack, RADIUS_ATTR_NAS_PORT_TYPE, 0, 0,
- _options.radiusnasporttype, NULL, 0);
- if (port) {
- char portid[16+1];
- snprintf(portid, sizeof(portid), "%.8d", port);
- radius_addattr(radius, pack, RADIUS_ATTR_NAS_PORT, 0, 0,
- port, NULL, 0);
- radius_addattr(radius, pack, RADIUS_ATTR_NAS_PORT_ID, 0, 0, 0,
- (uint8_t *) portid, strlen(portid));
- }
- /* Include his MAC address */
- if (hismac) {
- snprintf(mac, sizeof(mac), MAC_FMT, MAC_ARG(hismac));
- radius_addattr(radius, pack, RADIUS_ATTR_CALLING_STATION_ID, 0, 0, 0,
- (uint8_t*) mac, MACSTRLEN);
- }
- radius_addcalledstation(radius, pack, state);
- radius_addnasip(radius, pack);
- #ifdef ENABLE_PROXYVSA
- radius_addvsa(pack, &state->redir);
- #endif
- #ifdef ENABLE_LOCATION
- if (state->location[0]) {
- radius_addattr(radius, pack, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_LOCATION,
- 0, (uint8_t *) state->location,
- strlen(state->location));
- if (state->location_changes) {
- radius_addattr(radius, pack, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_LOCATION_CHANGE_COUNT,
- (uint32_t) state->location_changes, 0, 0);
- }
- }
- #endif
- /* Include NAS-Identifier if given in configuration options */
- if (_options.radiusnasid) {
- radius_addattr(radius, pack, RADIUS_ATTR_NAS_IDENTIFIER, 0, 0, 0,
- (uint8_t*) _options.radiusnasid, strlen(_options.radiusnasid));
- }
- if (_options.radiuslocationid) {
- radius_addattr(radius, pack, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_WISPR, RADIUS_ATTR_WISPR_LOCATION_ID, 0,
- (uint8_t*) _options.radiuslocationid,
- strlen(_options.radiuslocationid));
- }
- if (_options.radiuslocationname) {
- radius_addattr(radius, pack, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_WISPR, RADIUS_ATTR_WISPR_LOCATION_NAME, 0,
- (uint8_t*) _options.radiuslocationname,
- strlen(_options.radiuslocationname));
- }
- #ifdef ENABLE_MODULES
- { int i;
- for (i=0; i < MAX_MODULES; i++) {
- if (!_options.modules[i].name[0]) break;
- if (_options.modules[i].ctx) {
- struct chilli_module *m =
- (struct chilli_module *)_options.modules[i].ctx;
- if (m->radius_handler) {
- int res = m->radius_handler(radius, 0, pack, 0);
- switch (res) {
- case CHILLI_RADIUS_OK:
- break;
- default:
- return 0;
- }
- }
- }
- }
- }
- #endif
- return 0;
- }
- int chilli_auth_radius(struct radius_t *radius) {
- struct radius_packet_t radius_pack;
- int ret = -1;
- if (radius_default_pack(radius, &radius_pack, RADIUS_CODE_ACCESS_REQUEST)) {
- syslog(LOG_ERR, "radius_default_pack() failed");
- return ret;
- }
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_NAME, 0, 0, 0,
- (uint8_t *)_options.adminuser, strlen(_options.adminuser));
- if (_options.adminpasswd)
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_PASSWORD, 0, 0, 0,
- (uint8_t *)_options.adminpasswd, strlen(_options.adminpasswd));
- chilli_req_attrs(radius, &radius_pack,
- ACCT_USER,
- RADIUS_SERVICE_TYPE_ADMIN_USER, 0,
- 0, 0, 0,
- &admin_session.s_state);
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
- 0, 0, 0, NULL, RADIUS_MD5LEN);
- return radius_req(radius, &radius_pack, &admin_session);
- }
- int static auth_radius(struct app_conn_t *appconn,
- char *username, char *password,
- uint8_t *dhcp_pkt, size_t dhcp_len) {
- struct dhcp_conn_t *dhcpconn = (struct dhcp_conn_t *)appconn->dnlink;
- struct radius_packet_t radius_pack;
- char mac[MACSTRLEN+1];
- uint32_t service_type = RADIUS_SERVICE_TYPE_LOGIN;
- if (!radius) return -1;
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Starting radius authentication", __FUNCTION__, __LINE__);
- if (radius_default_pack(radius, &radius_pack, RADIUS_CODE_ACCESS_REQUEST)) {
- syslog(LOG_ERR, "radius_default_pack() failed");
- return -1;
- }
- /* Include his MAC address */
- snprintf(mac, sizeof(mac), MAC_FMT, MAC_ARG(dhcpconn->hismac));
- if (!username) {
- service_type = RADIUS_SERVICE_TYPE_FRAMED;
- strlcpy(appconn->s_state.redir.username, mac, USERNAMESIZE);
- if (_options.macsuffix) {
- size_t ulen = strlen(appconn->s_state.redir.username);
- strlcpy(appconn->s_state.redir.username + ulen,
- _options.macsuffix, USERNAMESIZE - ulen);
- }
- username = appconn->s_state.redir.username;
- } else {
- strlcpy(appconn->s_state.redir.username, username, USERNAMESIZE);
- }
- if (!password) {
- password = _options.macpasswd;
- if (!password) {
- password = appconn->s_state.redir.username;
- }
- }
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_NAME, 0, 0, 0,
- (uint8_t *) username, strlen(username));
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_PASSWORD, 0, 0, 0,
- (uint8_t *) password, strlen(password));
- appconn->authtype = PAP_PASSWORD;
- #ifdef ENABLE_DHCPRADIUS
- if (_options.dhcpradius && dhcp_pkt) {
- struct dhcp_tag_t *tag = 0;
- struct pkt_udphdr_t *udph = pkt_udphdr(dhcp_pkt);
- struct dhcp_packet_t *dhcppkt = pkt_dhcppkt(dhcp_pkt);
- #define maptag(OPT,VSA) tag=0; \
- if (!dhcp_gettag(dhcppkt, ntohs(udph->len)-PKT_UDP_HLEN, &tag, OPT)) { \
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC, \
- RADIUS_VENDOR_COOVACHILLI, VSA, 0, \
- (uint8_t *) tag->v, tag->l); }
- /*
- * Mapping of DHCP options to RADIUS Vendor Specific Attributes
- */
- maptag( DHCP_OPTION_PARAMETER_REQUEST_LIST,
- RADIUS_ATTR_COOVACHILLI_DHCP_PARAMETER_REQUEST_LIST );
- maptag( DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
- RADIUS_ATTR_COOVACHILLI_DHCP_VENDOR_CLASS_ID );
- maptag( DHCP_OPTION_CLIENT_IDENTIFIER,
- RADIUS_ATTR_COOVACHILLI_DHCP_CLIENT_ID );
- maptag( DHCP_OPTION_CLIENT_FQDN,
- RADIUS_ATTR_COOVACHILLI_DHCP_CLIENT_FQDN );
- maptag( DHCP_OPTION_HOSTNAME,
- RADIUS_ATTR_COOVACHILLI_DHCP_HOSTNAME );
- #undef maptag
- }
- #endif
- chilli_req_attrs(radius, &radius_pack,
- ACCT_USER, service_type, 0,
- appconn->unit, appconn->hismac,
- &appconn->hisip, &appconn->s_state);
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
- 0, 0, 0, NULL, RADIUS_MD5LEN);
- return radius_req(radius, &radius_pack, appconn);
- }
- #ifdef ENABLE_RADPROXY
- /*********************************************************
- * radius proxy functions
- * Used to send a response to a received radius request
- *********************************************************/
- /* Reply with an access reject */
- int static radius_access_reject(struct app_conn_t *conn) {
- struct radius_packet_t radius_pack;
- conn->radiuswait = 0;
- if (radius_default_pack(radius, &radius_pack, RADIUS_CODE_ACCESS_REJECT)) {
- syslog(LOG_ERR, "radius_default_pack() failed");
- return -1;
- }
- radius_pack.id = conn->radiusid;
- radius_resp(radius, &radius_pack, &conn->radiuspeer, conn->authenticator);
- return 0;
- }
- /* Reply with an access challenge */
- int static radius_access_challenge(struct app_conn_t *conn) {
- struct radius_packet_t radius_pack;
- size_t offset = 0;
- size_t eaplen = 0;
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Sending RADIUS AccessChallenge to client", __FUNCTION__, __LINE__);
- conn->radiuswait = 0;
- if (radius_default_pack(radius, &radius_pack, RADIUS_CODE_ACCESS_CHALLENGE)) {
- syslog(LOG_ERR, "radius_default_pack() failed");
- return -1;
- }
- radius_pack.id = conn->radiusid;
- /* Include EAP */
- do {
- if ((conn->challen - offset) > RADIUS_ATTR_VLEN)
- eaplen = RADIUS_ATTR_VLEN;
- else
- eaplen = conn->challen - offset;
- if (radius_addattr(radius, &radius_pack, RADIUS_ATTR_EAP_MESSAGE, 0, 0, 0,
- conn->chal + offset, eaplen)) {
- syslog(LOG_ERR, "radius_default_pack() failed");
- return -1;
- }
- offset += eaplen;
- }
- while (offset < conn->challen);
- if (conn->s_state.redir.statelen) {
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_STATE, 0, 0, 0,
- conn->s_state.redir.statebuf,
- conn->s_state.redir.statelen);
- }
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
- 0, 0, 0, NULL, RADIUS_MD5LEN);
- radius_resp(radius, &radius_pack, &conn->radiuspeer, conn->authenticator);
- return 0;
- }
- /* Send off an access accept */
- int static radius_access_accept(struct app_conn_t *conn) {
- struct radius_packet_t radius_pack;
- size_t offset = 0;
- size_t eaplen = 0;
- uint8_t mppekey[RADIUS_ATTR_VLEN];
- size_t mppelen;
- conn->radiuswait = 0;
- if (radius_default_pack(radius, &radius_pack, RADIUS_CODE_ACCESS_ACCEPT)) {
- syslog(LOG_ERR, "radius_default_pack() failed");
- return -1;
- }
- radius_pack.id = conn->radiusid;
- /* Include EAP (if present) */
- offset = 0;
- while (offset < conn->challen) {
- if ((conn->challen - offset) > RADIUS_ATTR_VLEN)
- eaplen = RADIUS_ATTR_VLEN;
- else
- eaplen = conn->challen - offset;
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_EAP_MESSAGE, 0, 0, 0,
- conn->chal + offset, eaplen);
- offset += eaplen;
- }
- if (conn->sendlen) {
- radius_keyencode(radius, mppekey, RADIUS_ATTR_VLEN,
- &mppelen, conn->sendkey,
- conn->sendlen, conn->authenticator,
- radius->proxysecret, radius->proxysecretlen);
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_MS, RADIUS_ATTR_MS_MPPE_SEND_KEY, 0,
- (uint8_t *)mppekey, mppelen);
- }
- if (conn->recvlen) {
- radius_keyencode(radius, mppekey, RADIUS_ATTR_VLEN,
- &mppelen, conn->recvkey,
- conn->recvlen, conn->authenticator,
- radius->proxysecret, radius->proxysecretlen);
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_MS, RADIUS_ATTR_MS_MPPE_RECV_KEY, 0,
- (uint8_t *)mppekey, mppelen);
- }
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
- 0, 0, 0, NULL, RADIUS_MD5LEN);
- radius_resp(radius, &radius_pack, &conn->radiuspeer, conn->authenticator);
- return 0;
- }
- #endif
- /*********************************************************
- * radius accounting functions
- * Used to send accounting request to radius server
- *********************************************************/
- static int acct_req(acct_type type,
- struct app_conn_t *conn, uint8_t status_type)
- {
- struct radius_packet_t radius_pack;
- uint32_t service_type = 0;
- uint32_t timediff;
- #ifdef ENABLE_GARDENACCOUNTING
- char incl_garden = 0;
- #endif
- switch(status_type) {
- case RADIUS_STATUS_TYPE_START:
- case RADIUS_STATUS_TYPE_ACCOUNTING_ON:
- conn->s_state.start_time = mainclock.tv_sec;
- conn->s_state.interim_time = mainclock.tv_sec;
- conn->s_state.last_time = mainclock.tv_sec;
- conn->s_state.last_up_time = mainclock.tv_sec;
- switch(type) {
- #ifdef ENABLE_GARDENACCOUNTING
- case ACCT_GARDEN:
- snprintf(conn->s_state.garden_sessionid,
- sizeof(conn->s_state.garden_sessionid),
- "UAM-%s-%.8x%.8x", inet_ntoa(conn->hisip),
- (int) mainclock_rt(), conn->unit);
- conn->s_state.garden_start_time = mainclock.tv_sec;
- conn->s_state.garden_interim_time = mainclock.tv_sec;
- conn->s_state.garden_input_octets = 0;
- conn->s_state.garden_output_octets = 0;
- conn->s_state.other_input_octets = 0;
- conn->s_state.other_output_octets = 0;
- break;
- #endif
- case ACCT_USER:
- conn->s_state.input_packets = 0;
- conn->s_state.output_packets = 0;
- conn->s_state.input_octets = 0;
- conn->s_state.output_octets = 0;
- break;
- }
- break;
- case RADIUS_STATUS_TYPE_INTERIM_UPDATE:
- conn->s_state.interim_time = mainclock.tv_sec;
- /* drop through */
- case RADIUS_STATUS_TYPE_STOP:
- switch(type) {
- #ifdef ENABLE_GARDENACCOUNTING
- case ACCT_GARDEN:
- conn->s_state.garden_interim_time = mainclock.tv_sec;
- if (!conn->s_state.garden_interim_time)
- return 0;
- #endif
- case ACCT_USER:
- break;
- }
- break;
- }
- /*
- * Return if there is no RADIUS accounting for this session.
- */
- if (conn->s_params.flags & NO_ACCOUNTING)
- return 0;
- /*
- * Build and send RADIUS Accounting.
- */
- if (radius_default_pack(radius, &radius_pack,
- RADIUS_CODE_ACCOUNTING_REQUEST)) {
- syslog(LOG_ERR, "radius_default_pack() failed");
- return -1;
- }
- if (RADIUS_STATUS_TYPE_ACCOUNTING_ON != status_type &&
- RADIUS_STATUS_TYPE_ACCOUNTING_OFF != status_type) {
- switch(type) {
- #ifdef ENABLE_GARDENACCOUNTING
- case ACCT_GARDEN:
- break;
- #endif
- case ACCT_USER:
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_NAME, 0, 0, 0,
- (uint8_t*) conn->s_state.redir.username,
- strlen(conn->s_state.redir.username));
- break;
- }
- if (conn->is_adminsession) {
- service_type = RADIUS_SERVICE_TYPE_ADMIN_USER;
- #ifdef ENABLE_GARDENACCOUNTING
- incl_garden = 1;
- #endif
- #if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
- {
- struct sysinfo the_info;
- if (sysinfo(&the_info)) {
- syslog(LOG_ERR, "%s: sysinfo()", strerror(errno));
- } else {
- float shiftfloat;
- float fav[3];
- char b[128];
- shiftfloat = (float) (1<<SI_LOAD_SHIFT);
- fav[0]=((float)the_info.loads[0])/shiftfloat;
- fav[1]=((float)the_info.loads[1])/shiftfloat;
- fav[2]=((float)the_info.loads[2])/shiftfloat;
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI, RADIUS_ATTR_COOVACHILLI_SYS_UPTIME,
- (uint32_t) the_info.uptime, NULL, 0);
- snprintf(b, sizeof(b), "%f %f %f",fav[0],fav[1],fav[2]);
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI, RADIUS_ATTR_COOVACHILLI_SYS_LOADAVG,
- 0, (uint8_t *) b, strlen(b));
- snprintf(b, sizeof(b), "%ld %ld %ld %ld",
- the_info.totalram,
- the_info.freeram,
- the_info.sharedram,
- the_info.bufferram);
- radius_addattr(radius, &radius_pack,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_SYS_MEMORY,
- 0, (uint8_t *) b, strlen(b));
- }
- }
- #endif
- }
- }
- if (status_type == RADIUS_STATUS_TYPE_STOP ||
- status_type == RADIUS_STATUS_TYPE_INTERIM_UPDATE) {
- switch(type) {
- #ifdef ENABLE_GARDENACCOUNTING
- case ACCT_GARDEN:
- incl_garden = 1;
- if (!conn->s_state.garden_start_time) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): session hasn't started yet", __FUNCTION__, __LINE__);
- return 0;
- }
- timediff = mainclock_diffu(conn->s_state.garden_start_time);
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_SESSION_TIME, 0, 0,
- timediff, NULL, 0);
- break;
- #endif
- case ACCT_USER:
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_INPUT_OCTETS, 0, 0,
- (uint32_t) conn->s_state.input_octets, NULL, 0);
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_OUTPUT_OCTETS, 0, 0,
- (uint32_t) conn->s_state.output_octets, NULL, 0);
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
- 0, 0, (uint32_t) (conn->s_state.input_octets >> 32), NULL, 0);
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
- 0, 0, (uint32_t) (conn->s_state.output_octets >> 32), NULL, 0);
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_INPUT_PACKETS, 0, 0,
- conn->s_state.input_packets, NULL, 0);
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_OUTPUT_PACKETS, 0, 0,
- conn->s_state.output_packets, NULL, 0);
- timediff = mainclock_diffu(conn->s_state.start_time);
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_SESSION_TIME, 0, 0,
- timediff, NULL, 0);
- break;
- }
- #ifdef ENABLE_GARDENACCOUNTING
- if (incl_garden && _options.uamgardendata) {
- radius_addattr(radius, &radius_pack,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_GARDEN_INPUT_OCTETS,
- (uint32_t) conn->s_state.garden_input_octets, NULL, 0);
- radius_addattr(radius, &radius_pack,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_GARDEN_OUTPUT_OCTETS,
- (uint32_t) conn->s_state.garden_output_octets, NULL, 0);
- radius_addattr(radius, &radius_pack,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_GARDEN_INPUT_GIGAWORDS,
- (uint32_t) (conn->s_state.garden_input_octets >> 32), NULL, 0);
- radius_addattr(radius, &radius_pack,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_GARDEN_OUTPUT_GIGAWORDS,
- (uint32_t) (conn->s_state.garden_output_octets >> 32), NULL, 0);
- if (_options.uamotherdata) {
- radius_addattr(radius, &radius_pack,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_OTHER_INPUT_OCTETS,
- (uint32_t) conn->s_state.other_input_octets, NULL, 0);
- radius_addattr(radius, &radius_pack,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_OTHER_OUTPUT_OCTETS,
- (uint32_t) conn->s_state.other_output_octets, NULL, 0);
- radius_addattr(radius, &radius_pack,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_OTHER_INPUT_GIGAWORDS,
- (uint32_t) (conn->s_state.other_input_octets >> 32), NULL, 0);
- radius_addattr(radius, &radius_pack,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_OTHER_OUTPUT_GIGAWORDS,
- (uint32_t) (conn->s_state.other_output_octets >> 32), NULL, 0);
- }
- }
- #endif
- }
- if (status_type == RADIUS_STATUS_TYPE_STOP ||
- status_type == RADIUS_STATUS_TYPE_ACCOUNTING_OFF) {
- switch(type) {
- #ifdef ENABLE_GARDENACCOUNTING
- case ACCT_GARDEN:
- break;
- #endif
- case ACCT_USER:
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
- 0, 0, conn->s_state.terminate_cause, NULL, 0);
- break;
- }
- }
- #ifdef ENABLE_SESSIONSTATE
- if (conn->s_state.session_state) {
- radius_addattr(radius, &radius_pack,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_SESSION_STATE,
- conn->s_state.session_state, 0, 0);
- }
- #endif
- chilli_req_attrs(radius, &radius_pack,
- type, service_type, status_type,
- conn->unit, conn->hismac,
- &conn->hisip,
- &conn->s_state);
- radius_req(radius, &radius_pack, conn);
- return 0;
- }
- #ifdef ENABLE_UAMANYIP
- /**
- * Assigns an ip from the dynamic pool, for SNAT'ing anyip connections.
- * If anyip is on and the clients address is outside of our network,
- * we need to SNAT to an ip of our network.
- */
- int chilli_assign_snat(struct app_conn_t *appconn, int force) {
- struct ippoolm_t *newipm;
- if (!_options.uamanyip) return 0;
- if (!_options.uamnatanyip) return 0;
- if (appconn->natip.s_addr && !force) return 0;
- /* check if excluded from anyip */
- if (_options.uamnatanyipex_addr.s_addr &&
- (appconn->hisip.s_addr & _options.uamnatanyipex_mask.s_addr) ==
- _options.uamnatanyipex_addr.s_addr) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Excluding ip %s from SNAT becuase it is in uamnatanyipex", __FUNCTION__, __LINE__,
- inet_ntoa(appconn->hisip));
- return 0;
- }
- if ((appconn->hisip.s_addr & _options.mask.s_addr) == _options.net.s_addr)
- return 0;
- if (_options.debug) {
- syslog(LOG_DEBUG, "%s(%d): Request SNAT ip for client ip: %s", __FUNCTION__, __LINE__,
- inet_ntoa(appconn->hisip));
- syslog(LOG_DEBUG, "%s(%d): SNAT mask: %s", __FUNCTION__, __LINE__, inet_ntoa(appconn->mask));
- syslog(LOG_DEBUG, "%s(%d): SNAT ourip: %s", __FUNCTION__, __LINE__, inet_ntoa(appconn->ourip));
- }
- if (ippool_newip(ippool, &newipm, &appconn->natip, 0)) {
- syslog(LOG_ERR, "Failed to allocate SNAT IP address");
- /*
- * Clean up the static pool listing too, it's misconfigured now.
- */
- if (appconn->dnlink) {
- dhcp_freeconn((struct dhcp_conn_t *)appconn->dnlink, 0);
- }
- return -1;
- }
- appconn->natip.s_addr = newipm->addr.s_addr;
- newipm->peer = appconn;
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): SNAT IP %s assigned", __FUNCTION__, __LINE__, inet_ntoa(appconn->natip));
- return 0;
- }
- #endif
- /***********************************************************
- *
- * Functions handling downlink protocol authentication.
- * Called in response to radius access request response.
- *
- ***********************************************************/
- int dnprot_reject(struct app_conn_t *appconn) {
- struct dhcp_conn_t* dhcpconn = NULL;
- /*struct ippoolm_t *ipm;*/
- if (appconn->is_adminsession) return 0;
- switch (appconn->dnprot) {
- #ifdef ENABLE_EAPOL
- case DNPROT_EAPOL:
- if (!(dhcpconn = (struct dhcp_conn_t*) appconn->dnlink)) {
- syslog(LOG_ERR, "No downlink protocol");
- return 0;
- }
- dhcp_sendEAPreject(dhcpconn, NULL, 0);
- return 0;
- #endif
- case DNPROT_UAM:
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Rejecting UAM", __FUNCTION__, __LINE__);
- return 0;
- #ifdef ENABLE_RADPROXY
- case DNPROT_WPA:
- return radius_access_reject(appconn);
- #endif
- case DNPROT_MAC:
- /* remove the username since we're not logged in */
- if (!appconn->s_state.authenticated)
- strlcpy(appconn->s_state.redir.username, "-", USERNAMESIZE);
- if (!(dhcpconn = (struct dhcp_conn_t *)appconn->dnlink)) {
- syslog(LOG_ERR, "No downlink protocol");
- return 0;
- }
- if (_options.macauthdeny) {
- dhcpconn->authstate = DHCP_AUTH_DROP;
- appconn->dnprot = DNPROT_NULL;
- }
- else {
- dhcpconn->authstate = DHCP_AUTH_DNAT;
- appconn->dnprot = DNPROT_UAM;
- }
- return 0;
- case DNPROT_NULL:
- #ifdef ENABLE_LAYER3
- case DNPROT_LAYER3:
- #endif
- return 0;
- default:
- syslog(LOG_ERR, "Unknown downlink protocol");
- return 0;
- }
- }
- #if defined(ENABLE_RADPROXY) || defined(ENABLE_EAPOL)
- int static dnprot_challenge(struct app_conn_t *appconn) {
- switch (appconn->dnprot) {
- #ifdef ENABLE_EAPOL
- case DNPROT_EAPOL:
- {
- struct dhcp_conn_t* dhcpconn = NULL;
- if (!(dhcpconn = (struct dhcp_conn_t *)appconn->dnlink)) {
- syslog(LOG_ERR, "No downlink protocol");
- return 0;
- }
- dhcp_sendEAP(dhcpconn, appconn->chal, appconn->challen);
- }
- break;
- #endif
- case DNPROT_NULL:
- case DNPROT_UAM:
- case DNPROT_MAC:
- #ifdef ENABLE_LAYER3
- case DNPROT_LAYER3:
- #endif
- break;
- #ifdef ENABLE_RADPROXY
- case DNPROT_WPA:
- radius_access_challenge(appconn);
- break;
- #endif
- default:
- syslog(LOG_ERR, "Unknown downlink protocol");
- }
- return 0;
- }
- #endif
- int dnprot_accept(struct app_conn_t *appconn) {
- struct dhcp_conn_t* dhcpconn = NULL;
- if (appconn->is_adminsession) return 0;
- if (!appconn->hisip.s_addr) {
- syslog(LOG_ERR, "IP address not allocated");
- return 0;
- }
- switch (appconn->dnprot) {
- #ifdef ENABLE_EAPOL
- case DNPROT_EAPOL:
- if (!(dhcpconn = (struct dhcp_conn_t *)appconn->dnlink)) {
- syslog(LOG_ERR, "No downlink protocol");
- return 0;
- }
- dhcp_set_addrs(dhcpconn,
- &appconn->hisip, &appconn->hismask,
- &appconn->ourip, &appconn->mask,
- &appconn->dns1, &appconn->dns2);
- /* This is the one and only place eapol authentication is accepted */
- dhcpconn->authstate = DHCP_AUTH_PASS;
- /* Tell client it was successful */
- dhcp_sendEAP(dhcpconn, appconn->chal, appconn->challen);
- syslog(LOG_WARNING, "Do not know how to set encryption keys on this platform!");
- break;
- #endif
- case DNPROT_UAM:
- if (!(dhcpconn = (struct dhcp_conn_t *)appconn->dnlink)) {
- syslog(LOG_ERR, "No downlink protocol");
- return 0;
- }
- dhcp_set_addrs(dhcpconn,
- &appconn->hisip, &appconn->hismask,
- &appconn->ourip, &appconn->mask,
- &appconn->dns1, &appconn->dns2);
- /* This is the one and only place UAM authentication is accepted */
- dhcpconn->authstate = DHCP_AUTH_PASS;
- appconn->s_params.flags &= ~REQUIRE_UAM_AUTH;
- break;
- #ifdef ENABLE_RADPROXY
- case DNPROT_WPA:
- if (!(dhcpconn = (struct dhcp_conn_t *)appconn->dnlink)) {
- syslog(LOG_ERR, "No downlink protocol");
- return 0;
- }
- dhcp_set_addrs(dhcpconn,
- &appconn->hisip, &appconn->hismask,
- &appconn->ourip, &appconn->mask,
- &appconn->dns1, &appconn->dns2);
- /* This is the one and only place WPA authentication is accepted */
- if (appconn->s_params.flags & REQUIRE_UAM_AUTH) {
- appconn->dnprot = DNPROT_DHCP_NONE;
- dhcpconn->authstate = DHCP_AUTH_NONE;
- }
- else {
- dhcpconn->authstate = DHCP_AUTH_PASS;
- }
- /* Tell access point it was successful */
- radius_access_accept(appconn);
- break;
- #endif
- case DNPROT_MAC:
- if (!(dhcpconn = (struct dhcp_conn_t *)appconn->dnlink)) {
- syslog(LOG_ERR, "No downlink protocol");
- return 0;
- }
- dhcp_set_addrs(dhcpconn,
- &appconn->hisip, &appconn->hismask,
- &appconn->ourip, &appconn->mask,
- &appconn->dns1, &appconn->dns2);
- dhcpconn->authstate = DHCP_AUTH_PASS;
- break;
- case DNPROT_NULL:
- case DNPROT_DHCP_NONE:
- return 0;
- #ifdef ENABLE_LAYER3
- case DNPROT_LAYER3:
- break;
- #endif
- default:
- syslog(LOG_ERR, "Unknown downlink protocol");
- return 0;
- }
- if ((dhcpconn && appconn->s_params.flags & REQUIRE_UAM_SPLASH) ||
- (dhcpconn && appconn->s_params.flags & REQUIRE_UAM_AUTH))
- dhcpconn->authstate = DHCP_AUTH_SPLASH;
- if (!(appconn->s_params.flags & REQUIRE_UAM_AUTH)) {
- /* This is the one and only place state is switched to authenticated */
- appconn->s_state.authenticated = 1;
- #ifdef ENABLE_SESSIONSTATE
- appconn->s_state.session_state =
- RADIUS_VALUE_COOVACHILLI_SESSION_AUTH;
- #endif
- #ifdef HAVE_NETFILTER_COOVA
- if (_options.kname) {
- kmod_coova_update(appconn);
- }
- #endif
- #ifdef ENABLE_MODULES
- { int i;
- for (i=0; i < MAX_MODULES; i++) {
- if (!_options.modules[i].name[0]) break;
- if (_options.modules[i].ctx) {
- struct chilli_module *m =
- (struct chilli_module *)_options.modules[i].ctx;
- if (m->session_start)
- m->session_start(appconn);
- }
- }
- }
- #endif
- /* if (!(appconn->s_params.flags & IS_UAM_REAUTH))*/
- acct_req(ACCT_USER, appconn, RADIUS_STATUS_TYPE_START);
- /* Run connection up script */
- if (_options.conup && !(appconn->s_params.flags & NO_SCRIPT)) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Calling connection up script: %s\n", __FUNCTION__, __LINE__, _options.conup);
- runscript(appconn, _options.conup, 0, 0);
- }
- }
- appconn->s_params.flags &= ~IS_UAM_REAUTH;
- #ifdef ENABLE_STATFILE
- if (_options.statusfilesave)
- printstatus();
- #endif
- return 0;
- }
- #ifdef ENABLE_SSDP
- static int fwd_ssdp(struct in_addr *dst,
- struct pkt_ipphdr_t *iph,
- struct pkt_udphdr_t *udph,
- struct pkt_buffer *pb,
- int ethhdr) {
- struct pkt_ethhdr_t *ethh = pkt_ethhdr(pkt_buffer_head(pb));
- if (udph && dst->s_addr == ssdp.s_addr) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): src="MAC_FMT" "
- "dst="MAC_FMT" prot=%.4x", __FUNCTION__, __LINE__,
- MAC_ARG(ethh->src),
- MAC_ARG(ethh->dst),
- ntohs(ethh->prot));
- /* TODO: also check that the source is from this machine in case we
- * are forwarding packets that we dont want to. */
- if (_options.debug) {
- char *bufr = (char *)(((void *)udph) + sizeof(struct pkt_udphdr_t));
- struct in_addr src;
- src.s_addr = iph->saddr;
- syslog(LOG_DEBUG, "%s(%d): ssdp multicast from %s\n%.*s", __FUNCTION__, __LINE__, inet_ntoa(src),
- ntohs(udph->len), bufr);
- }
- /* This sends to a unicast MAC address but a multicast IP address.
- */
- struct dhcp_conn_t *conn = dhcp->firstusedconn;
- while (conn) {
- if (conn->inuse && conn->authstate == DHCP_AUTH_PASS) {
- /*
- if (_options.debug)
- syslog(LOG_DEBUG, "sending to %s.", inet_ntoa(conn->hisip ));
- */
- dhcp_data_req(conn, pb, ethhdr);
- }
- conn = conn->next;
- }
- return 1; /* match */
- }
- return 0; /* no match */
- }
- #endif
- #ifdef ENABLE_LAYER3
- static int fwd_layer3(struct app_conn_t *appconn,
- struct in_addr *dst,
- struct pkt_udphdr_t *udph,
- struct pkt_buffer *pb,
- int ethhdr) {
- if (udph && udph->src == htons(DHCP_BOOTPS)) {
- struct dhcp_packet_t *pdhcp =
- (struct dhcp_packet_t *)(((void *)udph) + PKT_UDP_HLEN);
- if (pdhcp && pdhcp->op == DHCP_BOOTREPLY &&
- pdhcp->options[0] == 0x63 &&
- pdhcp->options[1] == 0x82 &&
- pdhcp->options[2] == 0x53 &&
- pdhcp->options[3] == 0x63) {
- if (!appconn) {
- struct in_addr src;
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Detecting layer3 IP assignment", __FUNCTION__, __LINE__);
- src.s_addr = pdhcp->yiaddr;
- appconn = chilli_connect_layer3(&src, 0);
- if (!appconn) {
- syslog(LOG_ERR, "could not allocate for %s", inet_ntoa(src));
- return 1;
- }
- }
- #ifdef ENABLE_TAP
- if (_options.usetap) {
- struct pkt_ethhdr_t *ethh = pkt_ethhdr(pkt_buffer_head(pb));
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): forwarding layer3 dhcp-broadcast: %s",__FUNCTION__, __LINE__, inet_ntoa(*dst));
- dhcp_send(dhcp, -1, ethh->dst,
- pkt_buffer_head(pb),
- pkt_buffer_length(pb));
- } else
- #endif
- {
- struct pkt_ethhdr_t *ethh;
- uint8_t packet[PKT_MAX_LEN];
- size_t length = pkt_buffer_length(pb);
- size_t hdrlen = PKT_ETH_HLEN;
- memset(packet, 0, hdrlen);
- ethh = pkt_ethhdr(packet);
- uint8_t *dstmac = pdhcp->chaddr;
- memcpy(packet + hdrlen,
- pkt_buffer_head(pb),
- pkt_buffer_length(pb));
- length += hdrlen;
- copy_mac6(ethh->dst, dstmac);
- copy_mac6(ethh->src, dhcp_nexthop(dhcp));
- ethh->prot = htons(PKT_ETH_PROTO_IP);
- dhcp_send(dhcp, -1, dstmac, packet, length);
- }
- return 1;
- }
- }
- return 0;
- }
- #endif
- /*
- * Tun callbacks
- *
- * Called from the tun_decaps function. This method is passed either
- * a Ethernet frame or an IP packet.
- */
- int cb_tun_ind(struct tun_t *tun, struct pkt_buffer *pb, int idx) {
- struct in_addr dst;
- struct ippoolm_t *ipm;
- struct app_conn_t *appconn = 0;
- struct pkt_udphdr_t *udph = 0;
- struct pkt_ipphdr_t *ipph;
- uint8_t *pack = pkt_buffer_head(pb);
- size_t len = pkt_buffer_length(pb);
- int ethhdr = (tun(tun, idx).flags & NET_ETHHDR) != 0;
- size_t ip_len = len;
- #ifdef ENABLE_TAP
- if (idx) ethhdr = 0;
- if (ethhdr) {
- struct pkt_ethhdr_t *ethh = 0;
- /*
- * Will never be 802.1Q
- */
- uint16_t prot;
- ethh = pkt_ethhdr(pack);
- prot = ntohs(ethh->prot);
- ipph = (struct pkt_ipphdr_t *)((char *)pack + PKT_ETH_HLEN);
- ip_len -= PKT_ETH_HLEN;
- switch (prot) {
- case PKT_ETH_PROTO_IPv6:
- return 0;
- case PKT_ETH_PROTO_IP:
- break;
- case PKT_ETH_PROTO_ARP:
- {
- /*
- * Send arp reply
- */
- uint8_t packet[PKT_BUFFER];
- struct pkt_ethhdr_t *p_ethh = pkt_ethhdr(pack);
- struct arp_packet_t *p_arp = pkt_arppkt(pack);
- struct pkt_ethhdr_t *packet_ethh = pkt_ethhdr(packet);
- struct arp_packet_t *packet_arp =
- ((struct arp_packet_t *)(((uint8_t*)(packet)) + PKT_ETH_HLEN));
- size_t length = PKT_ETH_HLEN + sizeof(struct arp_packet_t);
- struct in_addr reqaddr;
- /*
- * Get local copy of the target address to resolve
- */
- memcpy(&reqaddr.s_addr, p_arp->tpa, PKT_IP_ALEN);
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): arp: ifidx=%d src="MAC_FMT" "
- "dst="MAC_FMT" "
- "prot=%.4x (asking for %s)", __FUNCTION__, __LINE__,
- tun(tun,idx).ifindex,
- MAC_ARG(ethh->src),
- MAC_ARG(ethh->dst),
- ntohs(ethh->prot),
- inet_ntoa(reqaddr));
- /*
- * Lookup request address, see if we control it.
- */
- if (ippool_getip(ippool, &ipm, &reqaddr)) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): ARP for unknown IP %s", __FUNCTION__, __LINE__, inet_ntoa(reqaddr));
- return 0;
- }
- if ((appconn = (struct app_conn_t *)ipm->peer) == NULL ||
- (appconn->dnlink) == NULL) {
- syslog(LOG_ERR, "No peer protocol defined for ARP request");
- return 0;
- }
- /* Get packet default values */
- memset(&packet, 0, sizeof(packet));
- /* ARP Payload */
- packet_arp->hrd = htons(DHCP_HTYPE_ETH);
- packet_arp->pro = htons(PKT_ETH_PROTO_IP);
- packet_arp->hln = PKT_ETH_ALEN;
- packet_arp->pln = PKT_IP_ALEN;
- packet_arp->op = htons(DHCP_ARP_REPLY);
- /* Source address */
- /*memcpy(packet_arp->sha, appconn->hismac, PKT_ETH_ALEN);*/
- memcpy(packet_arp->sha, dhcp->rawif[0].hwaddr, PKT_ETH_ALEN);
- #ifdef ENABLE_UAMANYIP
- /*
- * ARP replies need to tell the NATed ip address,
- * when client is an anyip client.
- */
- if (_options.uamanyip && appconn->natip.s_addr) {
- memcpy(packet_arp->spa, &appconn->natip.s_addr, PKT_IP_ALEN);
- if (_options.debug) {
- char ip[56];
- char snatip[56];
- strlcpy(ip, inet_ntoa(appconn->hisip), sizeof(ip));
- strlcpy(snatip, inet_ntoa(appconn->natip), sizeof(snatip));
- syslog(LOG_DEBUG, "%s(%d): SNAT anyip in ARP response from %s to %s", __FUNCTION__, __LINE__,
- ip, snatip);
- }
- } else
- #endif
- memcpy(packet_arp->spa, &appconn->hisip.s_addr, PKT_IP_ALEN);
- /* Target address */
- memcpy(packet_arp->tha, p_arp->sha, PKT_ETH_ALEN);
- memcpy(packet_arp->tpa, p_arp->spa, PKT_IP_ALEN);
- /* Ethernet header */
- memcpy(packet_ethh->dst, p_ethh->src, PKT_ETH_ALEN);
- /*memcpy(packet_ethh->src, appconn->hismac, PKT_ETH_ALEN);*/
- memcpy(packet_ethh->src, dhcp->rawif[0].hwaddr, PKT_ETH_ALEN);
- packet_ethh->prot = htons(PKT_ETH_PROTO_ARP);
- if (_options.debug) {
- syslog(LOG_DEBUG, "%s(%d): arp-reply: src="MAC_FMT" "
- "dst="MAC_FMT, __FUNCTION__, __LINE__,
- MAC_ARG(packet_ethh->src),
- MAC_ARG(packet_ethh->dst));
- memcpy(&reqaddr.s_addr, packet_arp->spa, PKT_IP_ALEN);
- syslog(LOG_DEBUG, "%s(%d): arp-reply: source sha="MAC_FMT" spa=%s", __FUNCTION__, __LINE__,
- MAC_ARG(packet_arp->sha),
- inet_ntoa(reqaddr));
- memcpy(&reqaddr.s_addr, packet_arp->tpa, PKT_IP_ALEN);
- syslog(LOG_DEBUG, "%s(%d): arp-reply: target tha="MAC_FMT" tpa=%s", __FUNCTION__, __LINE__,
- MAC_ARG(packet_arp->tha),
- inet_ntoa(reqaddr));
- }
- return tun_write(tun, (uint8_t *)&packet, length, idx);
- }
- default:
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): unhandled protocol %x", __FUNCTION__, __LINE__, prot);
- return 0;
- }
- } else
- #endif
- {
- ipph = (struct pkt_ipphdr_t *)pack;
- }
- size_t hlen = (ipph->version_ihl & 0x0f) << 2;
- if (ntohs(ipph->tot_len) > ip_len || hlen > ip_len) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): invalid IP packet %d / %zu", __FUNCTION__, __LINE__,
- ntohs(ipph->tot_len),
- len);
- return 0;
- }
- /*
- * Filter out unsupported / unhandled protocols,
- * and check some basic length sanity.
- */
- switch(ipph->protocol) {
- case PKT_IP_PROTO_GRE:
- case PKT_IP_PROTO_TCP:
- case PKT_IP_PROTO_ICMP:
- case PKT_IP_PROTO_ESP:
- case PKT_IP_PROTO_AH:
- break;
- case PKT_IP_PROTO_UDP:
- {
- /*
- * Only the first IP fragment has the UDP header.
- */
- if (iphdr_offset((struct pkt_iphdr_t*)ipph) == 0) {
- udph = (struct pkt_udphdr_t *)(((void *)ipph) + hlen);
- }
- if (udph && !iphdr_more_frag((struct pkt_iphdr_t*)ipph) && (ntohs(udph->len) > ip_len)) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): invalid UDP packet %d / %d / %zu", __FUNCTION__, __LINE__,
- ntohs(ipph->tot_len),
- udph ? ntohs(udph->len) : -1, ip_len);
- return 0;
- }
- }
- break;
- default:
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): dropping unhandled packet: %x", __FUNCTION__, __LINE__, ipph->protocol);
- return 0;
- }
- dst.s_addr = ipph->daddr;
- #if(_debug_ > 1)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): sending to : %s", __FUNCTION__, __LINE__, inet_ntoa(dst));
- #endif
- if (ippool_getip(ippool, &ipm, &dst)) {
- /*
- * TODO: If within statip range, allow the packet through (?)
- */
- #ifdef ENABLE_SSDP
- if (fwd_ssdp(&dst, ipph, udph, pb, ethhdr)) return 0;
- #endif
- #ifdef ENABLE_LAYER3
- if (_options.layer3)
- if (fwd_layer3(0, &dst, udph, pb, ethhdr))
- return 0;
- #endif
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): dropping packet with unknown destination: %s", __FUNCTION__, __LINE__, inet_ntoa(dst));
- return 0;
- }
- appconn = (struct app_conn_t *)ipm->peer;
- #ifdef ENABLE_LEAKYBUCKET
- if (_options.scalewin && appconn && appconn->s_state.bucketdownsize) {
- uint16_t win = appconn->s_state.bucketdownsize -
- appconn->s_state.bucketdown;
- //log_dbg("window scaling to %d", win);
- pkt_shape_tcpwin((struct pkt_iphdr_t *)ipph, win);
- }
- #endif
- #ifdef ENABLE_LAYER3
- if (_options.layer3 && appconn && !appconn->dnlink)
- if (fwd_layer3(appconn, &dst, udph, pb, ethhdr))
- return 0;
- #endif
- if (appconn == NULL || appconn->dnlink == NULL) {
- syslog(LOG_ERR, "No %s protocol defined for %s",
- appconn ? "dnlink" : "peer", inet_ntoa(dst));
- return 0;
- }
- #ifdef ENABLE_UAMANYIP
- /**
- * connection needs to be NAT'ed, since client is an anyip client
- * outside of our network.
- * So, let's NAT the SNAT ip back to it's client ip.
- */
- if (_options.uamanyip && appconn->natip.s_addr) {
- #if(_debug_ > 1)
- if (_options.debug) {
- char ip[56];
- char snatip[56];
- strlcpy(ip, inet_ntoa(appconn->hisip), sizeof(ip));
- strlcpy(snatip, inet_ntoa(appconn->natip), sizeof(snatip));
- syslog(LOG_DEBUG, "%s(%d): SNAT anyip replace %s back to %s; snat was: %s", __FUNCTION__, __LINE__,
- inet_ntoa(dst), ip, snatip);
- }
- #endif
- ipph->daddr = appconn->hisip.s_addr;
- if (chksum((struct pkt_iphdr_t *) ipph) < 0)
- return 0;
- }
- #endif
- /* If the ip src is uamlisten and psrc is uamport
- we won't call leaky_bucket */
- if ( ! (ipph->saddr == _options.uamlisten.s_addr &&
- (ipph->sport == htons(_options.uamport)
- #ifdef ENABLE_UAMUIPORT
- || ipph->sport == htons(_options.uamuiport)
- #endif
- ))) {
- if (chilli_acct_tosub(appconn, ipph))
- return 0;
- }
- switch (appconn->dnprot) {
- case DNPROT_NULL:
- case DNPROT_DHCP_NONE:
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Dropping...", __FUNCTION__, __LINE__);
- break;
- case DNPROT_UAM:
- case DNPROT_WPA:
- case DNPROT_MAC:
- #ifdef ENABLE_EAPOL
- case DNPROT_EAPOL:
- #endif
- #ifdef ENABLE_LAYER3
- case DNPROT_LAYER3:
- #endif
- dhcp_data_req((struct dhcp_conn_t *)appconn->dnlink, pb, ethhdr);
- break;
- default:
- syslog(LOG_ERR, "Unknown downlink protocol: %d", appconn->dnprot);
- break;
- }
- return 0;
- }
- /*********************************************************
- *
- * Redir callbacks
- *
- *********************************************************/
- int cb_redir_getstate(struct redir_t *redir,
- struct sockaddr_in *address,
- struct sockaddr_in *baddress,
- struct redir_conn_t *conn) {
- struct in_addr *addr = &address->sin_addr;
- struct ippoolm_t *ipm;
- struct app_conn_t *appconn;
- struct dhcp_conn_t *dhcpconn;
- uint8_t flags = 0;
- #if defined(HAVE_NETFILTER_QUEUE) || defined(HAVE_NETFILTER_COOVA)
- if (_options.uamlisten.s_addr != _options.dhcplisten.s_addr) {
- addr->s_addr = addr->s_addr & ~(_options.mask.s_addr);
- addr->s_addr |= _options.dhcplisten.s_addr & _options.mask.s_addr;
- }
- #endif
- if (ippool_getip(ippool, &ipm, addr)) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): did not find %s", __FUNCTION__, __LINE__, inet_ntoa(*addr));
- return -1;
- }
- if ( (appconn = (struct app_conn_t *)ipm->peer) == NULL ||
- (dhcpconn = (struct dhcp_conn_t *)appconn->dnlink) == NULL ) {
- syslog(LOG_WARNING, "No peer protocol defined app-null=%d", appconn == 0);
- return -1;
- }
- conn->nasip = _options.radiuslisten;
- conn->nasport = appconn->unit;
- memcpy(conn->hismac, dhcpconn->hismac, PKT_ETH_ALEN);
- conn->ourip = appconn->ourip;
- conn->hisip = appconn->hisip;
- #ifdef HAVE_SSL
- /*
- * Determine if the connection is SSL or not.
- */
- {
- int n;
- for (n=0; n < DHCP_DNAT_MAX; n++) {
- /*
- * First, search the dnat list to see if we are tracking the port.
- */
- /*syslog("%d(%d) == %d",ntohs(dhcpconn->dnat[n].src_port),ntohs(dhcpconn->dnat[n].dst_port),ntohs(address->sin_port));*/
- if (dhcpconn->dnat[n].src_port == address->sin_port) {
- if (dhcpconn->dnat[n].dst_port == htons(DHCP_HTTPS)
- #ifdef ENABLE_UAMUIPORT
- || (_options.uamuissl && dhcpconn->dnat[n].dst_port == htons(_options.uamuiport))
- #endif
- ) {
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): redir connection is SSL", __FUNCTION__, __LINE__);
- #endif
- flags |= USING_SSL;
- }
- break;
- }
- }
- #ifdef ENABLE_UAMUIPORT
- /*
- * If not in dnat, if uamuissl is enabled, and this is indeed that
- * port, then we also know it is SSL (directly to https://uamlisten:uamuiport).
- */
- if (n == DHCP_DNAT_MAX && _options.uamuissl &&
- ntohs(baddress->sin_port) == _options.uamuiport) {
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): redir connection is SSL", __FUNCTION__, __LINE__);
- #endif
- flags |= USING_SSL;
- }
- #endif
- }
- #endif
- conn->flags = flags;
- memcpy(&conn->s_params, &appconn->s_params, sizeof(appconn->s_params));
- memcpy(&conn->s_state, &appconn->s_state, sizeof(appconn->s_state));
- /* reset state */
- appconn->uamexit = 0;
- return conn->s_state.authenticated == 1;
- }
- #ifdef ENABLE_LOCATION
- int
- chilli_learn_location(uint8_t *loc, int loclen,
- struct app_conn_t *appconn, char force) {
- char loc_buff[MAX_LOCATION_LENGTH];
- char prev_loc_buff[MAX_LOCATION_LENGTH];
- int prev_loc_len=0;
- char has_new_location = 0;
- char restart_accounting = 0;
- if (loclen >= MAX_LOCATION_LENGTH) {
- syslog(LOG_ERR, "Location too long %d", loclen);
- return 0;
- }
- memcpy(loc_buff, (char *)loc, loclen);
- loc_buff[loclen]=0;
- strlcpy(prev_loc_buff, appconn->s_state.location, sizeof(prev_loc_buff));
- prev_loc_len = strlen(prev_loc_buff);
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Learned location : [%.*s]", __FUNCTION__, __LINE__, loclen, loc);
- if (prev_loc_len == 0 ||
- prev_loc_len != loclen ||
- memcmp(prev_loc_buff, loc, prev_loc_len)) {
- if (force || !strcmp(appconn->s_state.pending_location,
- loc_buff)) {
- has_new_location = 1;
- appconn->s_state.location_changes++;
- appconn->s_state.pending_location[0]=0;
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Learned new-location : %d [%.*s] old %d [%s]", __FUNCTION__, __LINE__,
- loclen, loclen, loc,
- prev_loc_len, prev_loc_buff);
- #if defined(ENABLE_LOCATION) && defined(HAVE_AVL)
- location_add_conn(appconn, loc_buff);
- #endif
- if (_options.locationupdate) {
- runscript(appconn, _options.locationupdate,
- loc_buff, prev_loc_buff);
- }
- if (_options.location_stop_start) {
- restart_accounting = 1;
- }
- } else {
- strlcpy(appconn->s_state.pending_location, loc_buff,
- sizeof(appconn->s_state.pending_location));
- }
- }
- if (appconn->s_state.authenticated == 1 &&
- has_new_location && restart_accounting) {
- /* make sure not already over a limit ... */
- session_interval(appconn);
- #ifdef ENABLE_SESSIONSTATE
- appconn->s_state.session_state =
- RADIUS_VALUE_COOVACHILLI_SESSION_LOCATION_CHANGE;
- #endif
- if (appconn->s_state.authenticated == 1)
- acct_req(ACCT_USER, appconn, RADIUS_STATUS_TYPE_STOP);
- }
- #ifdef ENABLE_GARDENACCOUNTING
- if (_options.uamgardendata &&
- has_new_location && restart_accounting &&
- appconn->hisip.s_addr) {
- #ifdef ENABLE_SESSIONSTATE
- appconn->s_state.session_state =
- RADIUS_VALUE_COOVACHILLI_SESSION_LOCATION_CHANGE;
- #endif
- acct_req(ACCT_GARDEN, appconn, RADIUS_STATUS_TYPE_STOP);
- }
- #endif
- if (has_new_location) {
- memcpy(appconn->s_state.location, (char *) loc, loclen);
- appconn->s_state.location[loclen] = 0;
- }
- #ifdef ENABLE_GARDENACCOUNTING
- if (_options.uamgardendata &&
- has_new_location && restart_accounting &&
- appconn->hisip.s_addr) {
- acct_req(ACCT_GARDEN, appconn, RADIUS_STATUS_TYPE_START);
- }
- #endif
- if (appconn->s_state.authenticated == 1 &&
- has_new_location && restart_accounting) {
- /* adjust session parameters to be zeroed out */
- set_sessionid(appconn, 0);
- if (appconn->s_params.sessiontimeout) {
- uint32_t sessiontime = mainclock_diffu(appconn->s_state.start_time);
- if (sessiontime > appconn->s_params.sessiontimeout)
- /* (should be the case, having done the session_interval() above) */
- appconn->s_params.sessiontimeout -= sessiontime;
- }
- if (appconn->s_params.maxinputoctets) {
- if (appconn->s_params.maxinputoctets > appconn->s_state.input_octets)
- appconn->s_params.maxinputoctets -= appconn->s_state.input_octets;
- }
- if (appconn->s_params.maxoutputoctets) {
- if (appconn->s_params.maxoutputoctets > appconn->s_state.output_octets)
- appconn->s_params.maxoutputoctets -= appconn->s_state.output_octets;
- }
- if (appconn->s_params.maxtotaloctets) {
- uint64_t total = appconn->s_state.input_octets +
- appconn->s_state.output_octets;
- if (appconn->s_params.maxtotaloctets > total)
- appconn->s_params.maxtotaloctets -= total;
- }
- appconn->s_state.start_time = mainclock.tv_sec;
- appconn->s_state.interim_time = mainclock.tv_sec;
- appconn->s_state.last_time = mainclock.tv_sec;
- appconn->s_state.last_up_time = mainclock.tv_sec;
- appconn->s_state.input_packets = 0;
- appconn->s_state.input_octets = 0;
- appconn->s_state.output_packets = 0;
- appconn->s_state.output_octets = 0;
- acct_req(ACCT_USER, appconn, RADIUS_STATUS_TYPE_START);
- }
- else if (_options.location_immediate_update && has_new_location) {
- #ifdef ENABLE_SESSIONSTATE
- int old_state = appconn->s_state.session_state;
- appconn->s_state.session_state =
- RADIUS_VALUE_COOVACHILLI_SESSION_LOCATION_CHANGE;
- #endif
- if (appconn->s_state.authenticated == 1)
- acct_req(ACCT_USER, appconn, RADIUS_STATUS_TYPE_INTERIM_UPDATE);
- #ifdef ENABLE_GARDENACCOUNTING
- if (_options.uamgardendata)
- acct_req(ACCT_GARDEN, appconn, RADIUS_STATUS_TYPE_INTERIM_UPDATE);
- #endif
- #ifdef ENABLE_SESSIONSTATE
- appconn->s_state.session_state = old_state;
- #endif
- }
- return 0;
- }
- #endif
- #ifdef ENABLE_RADPROXY
- #if defined(ENABLE_LOCATION) || defined(ENABLE_PROXYVSA)
- static int
- chilli_proxy_radlocation(struct radius_packet_t *pack,
- struct app_conn_t *appconn, char force) {
- struct radius_attr_t *attr = 0;
- #ifdef ENABLE_PROXYVSA
- uint8_t * vsa = appconn->s_state.redir.vsa;
- int instance=0;
- #endif
- if (_options.location_copy_called) {
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_CALLED_STATION_ID, 0, 0, 0)) {
- if (attr->l - 2 < sizeof(appconn->s_state.redir.called) - 1) {
- appconn->s_state.redir.calledlen = attr->l - 2;
- memcpy(appconn->s_state.redir.called, attr->v.t,
- appconn->s_state.redir.calledlen);
- appconn->s_state.redir.called[appconn->s_state.redir.calledlen]=0;
- }
- }
- }
- #ifdef ENABLE_PROXYVSA
- do {
- attr=NULL;
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC, 0, 0,
- instance++)) {
- if ((appconn->s_state.redir.vsalen + (size_t) attr->l) >
- RADIUS_PROXYVSA) {
- syslog(LOG_WARNING, "VSAs too long");
- return -1;
- }
- memcpy(vsa + appconn->s_state.redir.vsalen,
- (void *)attr, (size_t) attr->l);
- appconn->s_state.redir.vsalen += (size_t) attr->l;
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Remembering VSA", __FUNCTION__, __LINE__);
- #endif
- }
- } while (attr);
- #endif
- #ifdef ENABLE_LOCATION
- if (_options.proxy_loc[0].attr) {
- int i;
- attr = 0;
- for (i=0; i < PROXYVSA_ATTR_CNT; i++) {
- if (!_options.proxy_loc[i].attr_vsa &&
- !_options.proxy_loc[i].attr)
- break;
- if (!_options.proxy_loc[i].attr_vsa) {
- /*
- * We have a loc_attr, but it isn't a VSA (so not included above)
- */
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): looking for attr %d", __FUNCTION__, __LINE__, _options.proxy_loc[i].attr);
- #endif
- if (radius_getattr(pack, &attr, _options.proxy_loc[i].attr,
- 0, 0, 0)) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): didn't find attr %d", __FUNCTION__, __LINE__, _options.proxy_loc[i].attr);
- attr = 0;
- }
- } else {
- /*
- * We have a loc_attr and VSA number (so it is included above).
- */
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): looking for attr %d/%d", __FUNCTION__, __LINE__, _options.proxy_loc[i].attr_vsa,
- _options.proxy_loc[i].attr);
- #endif
- if (radius_getattr(pack, &attr,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- _options.proxy_loc[i].attr_vsa,
- _options.proxy_loc[i].attr, 0)) {
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): didn't find attr %d/%d", __FUNCTION__, __LINE__, _options.proxy_loc[i].attr_vsa,
- _options.proxy_loc[i].attr);
- #endif
- attr = 0;
- }
- }
- }
- if (attr && attr->l > 2) {
- chilli_learn_location(attr->v.t, attr->l - 2, appconn, force);
- }
- }
- #endif
- return 0;
- }
- #endif
- /* Handle an accounting request */
- int accounting_request(struct radius_packet_t *pack,
- struct sockaddr_in *peer) {
- struct radius_attr_t *attr = NULL;
- struct radius_attr_t *hismacattr = NULL;
- struct radius_attr_t *nasipattr = NULL;
- struct radius_attr_t *nasportattr = NULL;
- struct radius_packet_t radius_pack;
- struct app_conn_t *appconn = NULL;
- struct dhcp_conn_t *dhcpconn = NULL;
- uint8_t hismac[PKT_ETH_ALEN];
- char macstr[RADIUS_ATTR_VLEN];
- size_t macstrlen;
- unsigned int temp[PKT_ETH_ALEN];
- uint32_t nasip = 0;
- uint32_t nasport = 0;
- int status_type;
- int i;
- if (radius_default_pack(radius, &radius_pack,
- RADIUS_CODE_ACCOUNTING_RESPONSE)) {
- syslog(LOG_ERR, "radius_default_pack() failed");
- return -1;
- }
- /* We will only respond, not proxy */
- radius_pack.id = pack->id;
- /* Status type */
- if (radius_getattr(pack, &attr, RADIUS_ATTR_ACCT_STATUS_TYPE, 0, 0, 0)) {
- syslog(LOG_ERR, "Status type is missing from radius request");
- radius_resp(radius, &radius_pack, peer, pack->authenticator);
- return 0;
- }
- status_type = ntohl(attr->v.i);
- if (RADIUS_STATUS_TYPE_ACCOUNTING_ON != status_type &&
- RADIUS_STATUS_TYPE_ACCOUNTING_OFF != status_type) {
- /* NAS IP */
- if (!radius_getattr(pack, &nasipattr,
- RADIUS_ATTR_NAS_IP_ADDRESS, 0, 0, 0)) {
- if ((nasipattr->l-2) != sizeof(appconn->nasip)) {
- syslog(LOG_ERR, "Wrong length of NAS IP address");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- nasip = nasipattr->v.i;
- }
- /* NAS PORT */
- if (!radius_getattr(pack, &nasportattr,
- RADIUS_ATTR_NAS_PORT, 0, 0, 0)) {
- if ((nasportattr->l-2) != sizeof(appconn->nasport)) {
- syslog(LOG_ERR, "Wrong length of NAS port");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- nasport = nasportattr->v.i;
- }
- /* Calling Station ID (MAC Address) */
- if (!radius_getattr(pack, &hismacattr,
- RADIUS_ATTR_CALLING_STATION_ID, 0, 0, 0)) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Calling Station ID is: %.*s", __FUNCTION__, __LINE__,
- hismacattr->l-2, hismacattr->v.t);
- if ((macstrlen = (size_t)hismacattr->l-2) >= (RADIUS_ATTR_VLEN-1)) {
- syslog(LOG_ERR, "Wrong length of called station ID");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- memcpy(macstr, hismacattr->v.t, macstrlen);
- macstr[macstrlen] = 0;
- /* Replace anything but hex with space */
- for (i=0; i<macstrlen; i++)
- if (!isxdigit((int) macstr[i]))
- macstr[i] = 0x20;
- if (sscanf (macstr, "%2x %2x %2x %2x %2x %2x",
- &temp[0], &temp[1], &temp[2],
- &temp[3], &temp[4], &temp[5]) != 6) {
- syslog(LOG_ERR, "Failed to convert Calling Station ID to MAC Address");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- for (i = 0; i < PKT_ETH_ALEN; i++)
- hismac[i] = temp[i];
- }
- if (hismacattr) {
- /*
- * Look for mac address.
- * If not found allocate new..
- */
- #ifdef ENABLE_LAYER3
- if (_options.layer3) {
- syslog(LOG_ERR, "Not supported in layer3 mode");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- } else {
- #endif
- if (dhcp_hashget(dhcp, &dhcpconn, hismac)) {
- if (dhcp_newconn(dhcp, &dhcpconn, hismac)) {
- syslog(LOG_ERR, "Out of connections");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- }
- if (!(dhcpconn->peer)) {
- syslog(LOG_ERR, "No peer protocol defined");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- appconn = (struct app_conn_t *)dhcpconn->peer;
- #ifdef ENABLE_LAYER3
- }
- #endif
- }
- else if (nasipattr && nasportattr) { /* Look for NAS IP / Port */
- if (chilli_getconn(&appconn, 0, nasip, nasport)) {
- syslog(LOG_ERR, "Unknown connection");
- radius_resp(radius, &radius_pack, peer, pack->authenticator);
- return 0;
- }
- }
- else {
- syslog(LOG_ERR, "Calling Station ID or NAS IP/Port is missing from radius request");
- radius_resp(radius, &radius_pack, peer, pack->authenticator);
- return 0;
- }
- if (!appconn) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): No application context for RADIUS proxy", __FUNCTION__, __LINE__);
- return 0;
- }
- /* Silently ignore radius request if allready processing one */
- if (appconn->radiuswait) {
- if (appconn->radiuswait == 2) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Giving up on previous packet.. not dropping this one", __FUNCTION__, __LINE__);
- appconn->radiuswait = 0;
- } else {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Dropping RADIUS while waiting", __FUNCTION__, __LINE__);
- appconn->radiuswait++;
- return 0;
- }
- }
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Handing RADIUS accounting proxy packet", __FUNCTION__, __LINE__);
- dhcpconn = (struct dhcp_conn_t*) appconn->dnlink;
- #ifdef ENABLE_APSESSIONID
- if (!radius_getattr(pack, &attr,
- RADIUS_ATTR_ACCT_SESSION_ID, 0, 0, 0)) {
- int len = attr->l-2;
- if (len >= sizeof(appconn->s_state.ap_sessionid))
- len = sizeof(appconn->s_state.ap_sessionid) - 1;
- memcpy(appconn->s_state.ap_sessionid, attr->v.t, len);
- appconn->s_state.ap_sessionid[len]=0;
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): AP Acct-Session-ID is: %s", __FUNCTION__, __LINE__,
- appconn->s_state.ap_sessionid);
- }
- #endif
- #if defined(ENABLE_LOCATION) || defined(ENABLE_PROXYVSA)
- switch (status_type) {
- case RADIUS_STATUS_TYPE_START:
- if (chilli_proxy_radlocation(pack, appconn, 1))
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- break;
- case RADIUS_STATUS_TYPE_INTERIM_UPDATE:
- case RADIUS_STATUS_TYPE_STOP:
- if (chilli_proxy_radlocation(pack, appconn, 0))
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- break;
- }
- #endif
- /* -- This needs to be optional --
- case RADIUS_STATUS_TYPE_STOP:
- if (!dhcpconn) {
- syslog(LOG_ERR,"No downlink protocol defined for RADIUS proxy client");
- return 0;
- }
- dhcp_freeconn(dhcpconn, RADIUS_TERMINATE_CAUSE_LOST_CARRIER);
- break;
- */
- }
- if (_options.proxyonacct) {
- /*
- * Drop the in-coming packet through to the chilli
- * RADIUS queue.
- */
- struct radius_packet_t acct_pack;
- if (!radius_default_pack(radius, &acct_pack,
- RADIUS_CODE_ACCOUNTING_REQUEST)) {
- size_t len = ntohs(pack->length) - RADIUS_HDRSIZE;
- memcpy(acct_pack.payload, pack->payload, len);
- acct_pack.length = htons(len + RADIUS_HDRSIZE);
- radius_req(radius, &acct_pack, appconn);
- }
- }
- radius_resp(radius, &radius_pack, peer, pack->authenticator);
- return 0;
- }
- int access_request(struct radius_packet_t *pack,
- struct sockaddr_in *peer) {
- struct radius_packet_t radius_pack;
- struct ippoolm_t *ipm = NULL;
- struct radius_attr_t *hisipattr = NULL;
- struct radius_attr_t *nasipattr = NULL;
- struct radius_attr_t *nasportattr = NULL;
- struct radius_attr_t *hismacattr = NULL;
- struct radius_attr_t *uidattr = NULL;
- struct radius_attr_t *pwdattr = NULL;
- struct radius_attr_t *eapattr = NULL;
- struct in_addr hisip;
- char pwd[RADIUS_ATTR_VLEN];
- size_t pwdlen;
- uint8_t hismac[PKT_ETH_ALEN];
- char macstr[RADIUS_ATTR_VLEN];
- size_t macstrlen;
- unsigned int temp[PKT_ETH_ALEN];
- int i;
- struct app_conn_t *appconn = NULL;
- struct dhcp_conn_t *dhcpconn = NULL;
- uint8_t resp[MAX_EAP_LEN]; /* EAP response */
- size_t resplen; /* Length of EAP response */
- size_t offset = 0;
- size_t eaplen = 0;
- int instance = 0;
- uint8_t qid;
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): RADIUS Access-Request received", __FUNCTION__, __LINE__);
- if (radius_default_pack(radius, &radius_pack, RADIUS_CODE_ACCESS_REJECT)) {
- syslog(LOG_ERR, "radius_default_pack() failed");
- return -1;
- }
- /* result of qnext */
- qid = radius_pack.id;
- /* keep in case of reject */
- radius_pack.id = pack->id;
- /*
- * User is identified by either IP address OR MAC address
- */
- /* Framed IP address (Conditional) */
- if (!radius_getattr(pack, &hisipattr,
- RADIUS_ATTR_FRAMED_IP_ADDRESS, 0, 0, 0)) {
- if ((hisipattr->l-2) != sizeof(hisip.s_addr)) {
- syslog(LOG_ERR, "Wrong length of framed IP address");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- hisip.s_addr = hisipattr->v.i;
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Framed IP address is: %s", __FUNCTION__, __LINE__, inet_ntoa(hisip));
- }
- /* Calling Station ID: MAC Address (Conditional) */
- if (!radius_getattr(pack, &hismacattr,
- RADIUS_ATTR_CALLING_STATION_ID, 0, 0, 0)) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Calling Station ID is: %.*s", __FUNCTION__, __LINE__, hismacattr->l-2, hismacattr->v.t);
- if ((macstrlen = (size_t)hismacattr->l-2) >= (RADIUS_ATTR_VLEN-1)) {
- syslog(LOG_ERR, "Wrong length of calling station ID");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- memcpy(macstr, hismacattr->v.t, macstrlen);
- macstr[macstrlen] = 0;
- /* Replace anything but hex with space */
- for (i=0; i<macstrlen; i++)
- if (!isxdigit((int) macstr[i]))
- macstr[i] = 0x20;
- if (sscanf (macstr, "%2x %2x %2x %2x %2x %2x",
- &temp[0], &temp[1], &temp[2],
- &temp[3], &temp[4], &temp[5]) != 6) {
- syslog(LOG_ERR, "Failed to convert Calling Station ID to MAC Address");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- for (i = 0; i < PKT_ETH_ALEN; i++)
- hismac[i] = temp[i];
- }
- /* Framed IP address or MAC Address must be given in request */
- if ((!hisipattr) && (!hismacattr)) {
- syslog(LOG_ERR, "Framed IP address or Calling Station ID is missing from radius request");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- /* Username (Mandatory) */
- if (radius_getattr(pack, &uidattr, RADIUS_ATTR_USER_NAME, 0, 0, 0)) {
- syslog(LOG_ERR, "User-Name is missing from radius request");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- if (hisipattr) { /* Find user based on IP address */
- if (ippool_getip(ippool, &ipm, &hisip)) {
- syslog(LOG_ERR, "RADIUS-Request: IP Address not found");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- if ((appconn = (struct app_conn_t *)ipm->peer) == NULL ||
- (dhcpconn = (struct dhcp_conn_t *)appconn->dnlink) == NULL) {
- syslog(LOG_ERR, "RADIUS-Request: No peer protocol defined");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- }
- else if (hismacattr) {
- /*
- * Look for mac address.
- * If not found allocate new..
- */
- #ifdef ENABLE_LAYER3
- if (_options.layer3) {
- syslog(LOG_ERR, "Not supported in layer3 mode");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- } else {
- #endif
- if (dhcp_hashget(dhcp, &dhcpconn, hismac)) {
- if (dhcp_newconn(dhcp, &dhcpconn, hismac)) {
- syslog(LOG_ERR, "Out of connections");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- }
- if (!(dhcpconn->peer)) {
- syslog(LOG_ERR, "No peer protocol defined");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- appconn = (struct app_conn_t *)dhcpconn->peer;
- #ifdef ENABLE_LAYER3
- }
- #endif
- }
- else {
- syslog(LOG_ERR, "Framed-IP-Address or Calling-Station-ID required in RADIUS request");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- /* Silently ignore radius request if already processing one */
- if (appconn->radiuswait) {
- if (appconn->radiuswait == 2) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Giving up on previous packet.. not dropping this one", __FUNCTION__, __LINE__);
- appconn->radiuswait = 0;
- } else {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Dropping RADIUS while waiting", __FUNCTION__, __LINE__);
- appconn->radiuswait++;
- return 0;
- }
- }
- dhcpconn->lasttime = mainclock_now();
- /* Password */
- if (!radius_getattr(pack, &pwdattr, RADIUS_ATTR_USER_PASSWORD, 0, 0, 0)) {
- if (radius_pwdecode(radius, (uint8_t*) pwd, RADIUS_ATTR_VLEN, &pwdlen,
- pwdattr->v.t, pwdattr->l-2, pack->authenticator,
- radius->proxysecret,
- radius->proxysecretlen)) {
- syslog(LOG_ERR, "radius_pwdecode() failed");
- return -1;
- }
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Password is: %s", __FUNCTION__, __LINE__, pwd);
- #endif
- }
- /* Get EAP message */
- resplen = 0;
- do {
- eapattr=NULL;
- if (!radius_getattr(pack, &eapattr, RADIUS_ATTR_EAP_MESSAGE, 0, 0,
- instance++)) {
- if ((resplen + (size_t)eapattr->l-2) > MAX_EAP_LEN) {
- syslog(LOG_INFO, "EAP message too long %zu %d", resplen, (int)eapattr->l-2);
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- memcpy(resp + resplen, eapattr->v.t, (size_t)eapattr->l-2);
- resplen += (size_t)eapattr->l-2;
- }
- } while (eapattr);
- if (resplen) {
- appconn->dnprot = DNPROT_WPA;
- }
- #if defined(ENABLE_LOCATION) || defined(ENABLE_PROXYVSA)
- if (chilli_proxy_radlocation(pack, appconn, 1))
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- #endif
- /* Passwd or EAP must be given in request */
- if ((!pwdattr) && (!resplen)) {
- syslog(LOG_ERR, "Password or EAP message is missing from radius request");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- #ifdef ENABLE_RADPROXY
- if (_options.proxymacaccept && !resplen) {
- syslog(LOG_INFO, "Accepting MAC login");
- radius_pack.code = RADIUS_CODE_ACCESS_ACCEPT;
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- #endif
- /* CoovaChilli Notes:
- Dublicate logins should be allowed as it might be the terminal
- moving from one access point to another. It is however
- unacceptable to login with another username on top of an allready
- existing connection
- TODO: New username should be allowed, but should result in
- a accounting stop message for the old connection.
- this does however pose a denial of service attack possibility
- If allready logged in send back accept message with username
- TODO ? Should this be a reject: Dont login twice ?
- */
- /* Terminate previous session if trying to login with another username */
- if ((appconn->s_state.authenticated == 1) &&
- ((strlen(appconn->s_state.redir.username) != uidattr->l-2) ||
- (memcmp(appconn->s_state.redir.username, uidattr->v.t, uidattr->l-2)))) {
- terminate_appconn(appconn, RADIUS_TERMINATE_CAUSE_USER_REQUEST);
- if (radius_default_pack(radius, &radius_pack, RADIUS_CODE_ACCESS_REJECT)) {
- syslog(LOG_ERR, "radius_default_pack() failed");
- return -1;
- }
- }
- /* NAS IP */
- if (!radius_getattr(pack, &nasipattr, RADIUS_ATTR_NAS_IP_ADDRESS, 0, 0, 0)) {
- if ((nasipattr->l-2) != sizeof(appconn->nasip)) {
- syslog(LOG_ERR, "Wrong length of NAS IP address");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- appconn->nasip = nasipattr->v.i;
- }
- /* NAS PORT */
- if (!radius_getattr(pack, &nasportattr, RADIUS_ATTR_NAS_PORT, 0, 0, 0)) {
- if ((nasportattr->l-2) != sizeof(appconn->nasport)) {
- syslog(LOG_ERR, "Wrong length of NAS port");
- return radius_resp(radius, &radius_pack, peer, pack->authenticator);
- }
- appconn->nasport = nasportattr->v.i;
- }
- /* Store parameters for later use */
- if (uidattr->l-2 < USERNAMESIZE) {
- memcpy(appconn->s_state.redir.username,
- (char *)uidattr->v.t, uidattr->l-2);
- appconn->s_state.redir.username[uidattr->l-2]=0;
- }
- appconn->radiuswait = 1;
- appconn->radiusid = pack->id;
- if (pwdattr)
- appconn->authtype = PAP_PASSWORD;
- else
- appconn->authtype = EAP_MESSAGE;
- memcpy(&appconn->radiuspeer, peer, sizeof(*peer));
- memcpy(appconn->authenticator, pack->authenticator, RADIUS_AUTHLEN);
- memcpy(appconn->hismac, dhcpconn->hismac, PKT_ETH_ALEN);
- /* Build up radius request */
- radius_pack.code = RADIUS_CODE_ACCESS_REQUEST;
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_NAME, 0, 0, 0,
- uidattr->v.t, uidattr->l - 2);
- if (appconn->s_state.redir.statelen) {
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_STATE, 0, 0, 0,
- appconn->s_state.redir.statebuf,
- appconn->s_state.redir.statelen);
- }
- if (pwdattr)
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_PASSWORD, 0, 0, 0,
- (uint8_t*) pwd, pwdlen);
- /* Include EAP (if present) */
- offset = 0;
- while (offset < resplen) {
- if ((resplen - offset) > RADIUS_ATTR_VLEN)
- eaplen = RADIUS_ATTR_VLEN;
- else
- eaplen = resplen - offset;
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_EAP_MESSAGE, 0, 0, 0,
- resp + offset, eaplen);
- offset += eaplen;
- }
- if (resplen) {
- if (_options.wpaguests)
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI, RADIUS_ATTR_COOVACHILLI_CONFIG,
- 0, (uint8_t*)"allow-wpa-guests", 16);
- }
- chilli_req_attrs(radius, &radius_pack,
- ACCT_USER,
- _options.framedservice ? RADIUS_SERVICE_TYPE_FRAMED :
- RADIUS_SERVICE_TYPE_LOGIN, 0,
- appconn->unit, appconn->hismac,
- &appconn->hisip, &appconn->s_state);
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
- 0, 0, 0, NULL, RADIUS_MD5LEN);
- /* restore request id to that of queue */
- radius_pack.id = qid;
- return radius_req(radius, &radius_pack, appconn);
- }
- /*********************************************************
- *
- * radius proxy callback functions (request from radius server)
- *
- *********************************************************/
- /* Radius callback when radius request has been received */
- int cb_radius_ind(struct radius_t *rp, struct radius_packet_t *pack,
- struct sockaddr_in *peer) {
- if (rp != radius) {
- syslog(LOG_ERR, "Radius callback from unknown instance");
- return 0;
- }
- switch (pack->code) {
- case RADIUS_CODE_ACCOUNTING_REQUEST:
- return accounting_request(pack, peer);
- case RADIUS_CODE_ACCESS_REQUEST:
- return access_request(pack, peer);
- default:
- syslog(LOG_ERR, "Unsupported radius request received: %d", pack->code);
- return 0;
- }
- }
- #endif
- static int
- session_disconnect(struct app_conn_t *appconn,
- struct dhcp_conn_t *dhcpconn,
- int term_cause) {
- #ifdef ENABLE_MODULES
- { int i;
- for (i=0; i < MAX_MODULES; i++) {
- if (!_options.modules[i].name[0]) break;
- if (_options.modules[i].ctx) {
- struct chilli_module *m =
- (struct chilli_module *)_options.modules[i].ctx;
- if (m->dhcp_disconnect)
- m->dhcp_disconnect(appconn, dhcpconn);
- }
- }
- }
- #endif
- terminate_appconn(appconn,
- term_cause ? term_cause :
- appconn->s_state.terminate_cause ?
- appconn->s_state.terminate_cause :
- RADIUS_TERMINATE_CAUSE_LOST_CARRIER);
- if (appconn->uplink) {
- struct ippoolm_t *member = (struct ippoolm_t *) appconn->uplink;
- #ifdef ENABLE_UAMANYIP
- if (_options.uamanyip) {
- if (!appconn->natip.s_addr) {
- if (member->in_use && member->is_static) {
- struct in_addr mask;
- int res;
- mask.s_addr = 0xffffffff;
- res = net_del_route(&member->addr, &appconn->ourip, &mask);
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Removing route: %s %d", __FUNCTION__, __LINE__, inet_ntoa(member->addr), res);
- }
- } else {
- struct ippoolm_t *natipm;
- if (ippool_getip(ippool, &natipm, &appconn->natip) == 0) {
- if (ippool_freeip(ippool, natipm)) {
- syslog(LOG_ERR, "ippool_freeip(%s) failed for nat ip!",
- inet_ntoa(appconn->natip));
- }
- }
- }
- }
- #endif
- if (member->in_use && (!dhcpconn || !dhcpconn->is_reserved)) {
- if (ippool_freeip(ippool, member)) {
- syslog(LOG_ERR, "ippool_freeip(%s) failed!",
- inet_ntoa(member->addr));
- }
- }
- #if defined(ENABLE_TAP) && defined(SIOCDARP)
- if (_options.usetap) {
- /*
- * USETAP ARP
- */
- int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (sockfd > 0) {
- struct arpreq req;
- memset(&req, 0, sizeof(req));
- SET_SA_FAMILY(req.arp_pa, AF_INET);
- ((struct sockaddr_in *) &req.arp_pa)->sin_addr.s_addr =
- appconn->hisip.s_addr;
- req.arp_flags = ATF_PERM | ATF_PUBL;
- strlcpy(req.arp_dev, tuntap(tun).devname, sizeof(req.arp_dev));
- if (ioctl(sockfd, SIOCDARP, &req) < 0) {
- perror("ioctrl()");
- }
- safe_close(sockfd);
- }
- }
- #endif
- }
- if (_options.macdown) {
- syslog(LOG_DEBUG, "%s(%d): Calling MAC down script: %s", __FUNCTION__, __LINE__, _options.macdown);
- runscript(appconn, _options.macdown, 0, 0);
- }
- if (!dhcpconn || !dhcpconn->is_reserved) {
- freeconn(appconn);
- if (dhcpconn)
- dhcpconn->peer = 0;
- }
- #ifdef ENABLE_BINSTATFILE
- if (_options.statusfilesave)
- printstatus();
- #endif
- return 0;
- }
- static int
- upprot_getip(struct app_conn_t *appconn,
- struct in_addr *hisip,
- struct in_addr *hismask) {
- struct ippoolm_t *ipm = 0;
- struct dhcp_conn_t *dhcpconn = (struct dhcp_conn_t *)appconn->dnlink;
- #if(_debug_ > 1)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): UPPROT - GETIP", __FUNCTION__, __LINE__);
- #endif
- /* If IP address is already allocated: Fill it in */
- /* This should only happen for UAM */
- if (appconn->uplink) {
- ipm = (struct ippoolm_t *)appconn->uplink;
- }
- if (ipm == 0) {
- /* Allocate static or dynamic IP address */
- if (newip(&ipm, hisip, dhcpconn ? dhcpconn->hismac : 0))
- return dnprot_reject(appconn);
- appconn->hisip.s_addr = ipm->addr.s_addr;
- if (hismask && hismask->s_addr)
- appconn->hismask.s_addr = hismask->s_addr;
- else
- appconn->hismask.s_addr = _options.mask.s_addr;
- /* TODO: Too many "listen" and "ourip" addresses! */
- if (!appconn->ourip.s_addr)
- appconn->ourip.s_addr = _options.dhcplisten.s_addr;
- appconn->uplink = ipm;
- ipm->peer = appconn;
- #ifdef ENABLE_GARDENACCOUNTING
- if (_options.uamgardendata) {
- acct_req(ACCT_GARDEN, appconn, RADIUS_STATUS_TYPE_START);
- }
- #endif
- }
- #ifdef ENABLE_UAMANYIP
- if (chilli_assign_snat(appconn, 0) != 0) {
- return -1;
- }
- #endif
- return dnprot_accept(appconn);
- }
- void session_param_defaults(struct session_params *params) {
- if (_options.defsessiontimeout && !params->sessiontimeout)
- params->sessiontimeout = _options.defsessiontimeout;
- if (_options.defidletimeout && !params->idletimeout)
- params->idletimeout = _options.defidletimeout;
- if (_options.defbandwidthmaxdown && !params->bandwidthmaxdown)
- params->bandwidthmaxdown = _options.defbandwidthmaxdown;
- if (_options.defbandwidthmaxup && !params->bandwidthmaxup)
- params->bandwidthmaxup = _options.defbandwidthmaxup;
- if (_options.definteriminterval && !params->interim_interval)
- params->interim_interval = _options.definteriminterval;
- }
- void
- config_radius_session(struct session_params *params,
- struct radius_packet_t *pack,
- struct app_conn_t *appconn,
- int reconfig) {
- struct radius_attr_t *attr = NULL;
- size_t offset = 0;
- /*int is_splash = 0;*/
- int seen;
- /* Session timeout */
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_SESSION_TIMEOUT, 0, 0, 0))
- params->sessiontimeout = ntohl(attr->v.i);
- else if (!reconfig)
- params->sessiontimeout = 0;
- /* Idle timeout */
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_IDLE_TIMEOUT, 0, 0, 0))
- params->idletimeout = ntohl(attr->v.i);
- else if (!reconfig)
- params->idletimeout = 0;
- /* Filter ID */
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_FILTER_ID, 0, 0, 0)) {
- params->filteridlen = attr->l-2;
- memcpy(params->filteridbuf, attr->v.t, attr->l-2);
- params->filteridbuf[attr->l-2] = 0;
- }
- else if (!reconfig) {
- params->filteridlen = 0;
- params->filteridbuf[0] = 0;
- }
- /* Interim interval */
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, 0, 0, 0)) {
- params->interim_interval = ntohl(attr->v.i);
- if (params->interim_interval < 60) {
- syslog(LOG_ERR, "Received too small radius Acct-Interim-Interval: %d; resettings to default.",
- params->interim_interval);
- params->interim_interval = 0;
- }
- }
- else if (!reconfig)
- params->interim_interval = 0;
- /* Bandwidth up */
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_WISPR,
- RADIUS_ATTR_WISPR_BANDWIDTH_MAX_UP, 0))
- params->bandwidthmaxup = ntohl(attr->v.i);
- else if (!reconfig)
- params->bandwidthmaxup = 0;
- /* Bandwidth down */
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_WISPR,
- RADIUS_ATTR_WISPR_BANDWIDTH_MAX_DOWN, 0))
- params->bandwidthmaxdown = ntohl(attr->v.i);
- else if (!reconfig)
- params->bandwidthmaxdown = 0;
- #ifdef RADIUS_ATTR_COOVACHILLI_BANDWIDTH_MAX_UP
- /* Bandwidth up */
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_BANDWIDTH_MAX_UP, 0))
- params->bandwidthmaxup = ntohl(attr->v.i) * 1000;
- #endif
- #ifdef RADIUS_ATTR_COOVACHILLI_BANDWIDTH_MAX_DOWN
- /* Bandwidth down */
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_BANDWIDTH_MAX_DOWN, 0))
- params->bandwidthmaxdown = ntohl(attr->v.i) * 1000;
- #endif
- /* Max input octets */
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_MAX_INPUT_OCTETS, 0))
- params->maxinputoctets = ntohl(attr->v.i);
- else if (!reconfig)
- params->maxinputoctets = 0;
- /* Max output octets */
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_MAX_OUTPUT_OCTETS, 0))
- params->maxoutputoctets = ntohl(attr->v.i);
- else if (!reconfig)
- params->maxoutputoctets = 0;
- /* Max total octets */
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_MAX_TOTAL_OCTETS, 0))
- params->maxtotaloctets = ntohl(attr->v.i);
- else if (!reconfig)
- params->maxtotaloctets = 0;
- /* Max input gigawords */
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_MAX_INPUT_GIGAWORDS, 0))
- params->maxinputoctets |= ((uint64_t)ntohl(attr->v.i) & 0xffffffff) << 32;
- /* Max output gigawords */
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_MAX_OUTPUT_GIGAWORDS, 0))
- params->maxoutputoctets |= ((uint64_t)ntohl(attr->v.i) & 0xffffffff) << 32;
- /* Max total octets */
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_MAX_TOTAL_GIGAWORDS, 0))
- params->maxtotaloctets |= ((uint64_t)ntohl(attr->v.i) & 0xffffffff) << 32;
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_REQUIRE_UAM, 0)) {
- memcpy(params->url, attr->v.t, attr->l-2);
- params->url[attr->l-2] = 0;
- }
- #ifdef ENABLE_REDIRINJECT
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_INJECT_URL, 0)) {
- memcpy(params->url, attr->v.t, attr->l-2);
- params->url[attr->l-2] = 0;
- params->flags |= UAM_INJECT_URL | REQUIRE_UAM_AUTH;
- }
- #endif
- #ifdef EX_CONFIG_RADIUS_SESSION
- #include EX_CONFIG_RADIUS_SESSION
- #endif
- #ifdef ENABLE_MULTIROUTE
- if (tun) {
- /* Route Index, look-up by interface name */
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_ROUTE_TO_INTERFACE, 0)) {
- char name[256];
- memcpy(name, attr->v.t, attr->l-2);
- name[attr->l-2] = 0;
- params->routeidx = tun_name2idx(tun, name);
- }
- else if (!reconfig) {
- params->routeidx = tun->routeidx;
- }
- }
- #endif
- #ifdef ENABLE_COOVACHILLICONFIG
- {
- /*
- * Looking for CoovaChilli-Config attributes with
- * special messages.
- */
- const char *adminreset = "admin-reset";
- const char *uamauth = "require-uam-auth";
- const char *splash = "splash";
- const char *logout = "logout";
- #ifdef ENABLE_SESSGARDEN
- const char *uamallowed = "uamallowed=";
- const int uamallowed_len = strlen(uamallowed);
- #endif
- while (!radius_getnextattr(pack, &attr,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_CONFIG,
- 0, &offset)) {
- size_t len = (size_t) attr->l - 2;
- char *val = (char *) attr->v.t;
- if (len == strlen(uamauth) && !memcmp(val, uamauth, len)) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): received require-uam-auth", __FUNCTION__, __LINE__);
- params->flags |= REQUIRE_UAM_AUTH;
- }
- else if (len == strlen(splash) && !memcmp(val, splash, len)) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): received splash response", __FUNCTION__, __LINE__);
- params->flags |= REQUIRE_UAM_SPLASH;
- /*is_splash = 1;*/
- }
- #ifdef ENABLE_SESSGARDEN
- else if (len > uamallowed_len && len < 255 &&
- !memcmp(val, uamallowed, uamallowed_len)) {
- char name[256];
- /* copy and null-terminate */
- len -= uamallowed_len;
- val += uamallowed_len;
- memcpy(name, val, len);
- name[len]=0;
- if (len == 5 && !memcmp(name,"reset",5)) {
- params->pass_through_count = 0;
- #ifdef HAVE_PATRICIA
- if (appconn && appconn->ptree) {
- patricia_destroy (appconn->ptree, free);
- appconn->ptree = NULL;
- }
- #endif
- } else {
- #ifdef HAVE_PATRICIA
- if (appconn && appconn->ptree == NULL)
- appconn->ptree = patricia_new (32);
- #endif
- pass_throughs_from_string(params->pass_throughs,
- SESSION_PASS_THROUGH_MAX,
- ¶ms->pass_through_count,
- name, 0, 0
- #ifdef HAVE_PATRICIA
- , appconn ? appconn->ptree : 0
- #endif
- );
- }
- }
- #endif
- else if (appconn && len >= strlen(logout) &&
- !memcmp(val, logout, strlen(logout))) {
- if (appconn)
- terminate_appconn(appconn,
- RADIUS_TERMINATE_CAUSE_USER_REQUEST);
- } else if (appconn && len >= strlen(adminreset) &&
- !memcmp(val, adminreset, strlen(adminreset))) {
- dhcp_release_mac(dhcp, appconn->hismac,
- RADIUS_TERMINATE_CAUSE_ADMIN_RESET);
- }
- }
- }
- #endif
- seen = 0;
- offset = 0;
- while (!radius_getnextattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_WISPR,
- RADIUS_ATTR_WISPR_REDIRECTION_URL,
- 0, &offset)) {
- ssize_t clen, nlen = (ssize_t) attr->l - 2;
- char *url = (char*) attr->v.t;
- if (seen == 0) { params->url[0]=0; seen=1; }
- clen = strlen((char*)params->url);
- if (clen + nlen > sizeof(params->url) - 1)
- nlen = sizeof(params->url) - clen - 1;
- if (nlen > 0) {
- memcpy(params->url + clen, url, nlen);
- params->url[clen + nlen] = 0;
- params->flags |= UAM_CLEAR_URL;
- }
- /*if (!is_splash) {
- params->flags |= REQUIRE_REDIRECT;
- }*/
- }
- /* Session-Terminate-Time */
- if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_WISPR,
- RADIUS_ATTR_WISPR_SESSION_TERMINATE_TIME, 0)) {
- char attrs[RADIUS_ATTR_VLEN + 1];
- struct tm stt;
- int tzhour, tzmin;
- char *tz;
- int result;
- memcpy(attrs, attr->v.t, attr->l-2);
- attrs[attr->l-2] = 0;
- memset(&stt, 0, sizeof(stt));
- result = sscanf(attrs, "%d-%d-%dT%d:%d:%d %d:%d",
- &stt.tm_year, &stt.tm_mon, &stt.tm_mday,
- &stt.tm_hour, &stt.tm_min, &stt.tm_sec,
- &tzhour, &tzmin);
- if (result == 8) { /* Timezone */
- /* tzhour and tzmin is hours and minutes east of GMT */
- /* timezone is defined as seconds west of GMT. Excludes DST */
- stt.tm_year -= 1900;
- stt.tm_mon -= 1;
- stt.tm_hour -= tzhour; /* Adjust for timezone */
- stt.tm_min -= tzmin; /* Adjust for timezone */
- /* stt.tm_hour += daylight;*/
- /*stt.tm_min -= (timezone / 60);*/
- tz = getenv("TZ");
- setenv("TZ", "", 1); /* Set environment to UTC */
- tzset();
- params->sessionterminatetime = mktime(&stt);
- if (tz) setenv("TZ", tz, 1);
- else unsetenv("TZ");
- tzset();
- }
- else if (result >= 6) { /* Local time */
- tzset();
- stt.tm_year -= 1900;
- stt.tm_mon -= 1;
- stt.tm_isdst = -1; /*daylight;*/
- params->sessionterminatetime = mktime(&stt);
- }
- else {
- params->sessionterminatetime = 0;
- syslog(LOG_WARNING, "Invalid WISPr-Session-Terminate-Time received: %s", attrs);
- }
- }
- else if (!reconfig)
- params->sessionterminatetime = 0;
- session_param_defaults(params);
- }
- static int chilliauth_cb(struct radius_t *radius,
- struct radius_packet_t *pack,
- struct radius_packet_t *pack_req,
- void *cbp) {
- struct radius_attr_t *attr = NULL;
- size_t offset = 0;
- if (!pack) {
- syslog(LOG_ERR, "Radius request timed out");
- return 0;
- }
- if ((pack->code != RADIUS_CODE_ACCESS_REJECT) &&
- (pack->code != RADIUS_CODE_ACCESS_CHALLENGE) &&
- (pack->code != RADIUS_CODE_ACCESS_ACCEPT)) {
- syslog(LOG_ERR, "Unknown radius access reply code %d", pack->code);
- return 0;
- }
- /* ACCESS-ACCEPT */
- if (pack->code != RADIUS_CODE_ACCESS_ACCEPT) {
- syslog(LOG_ERR, "Administrative-User Login Failed");
- return 0;
- }
- if (_options.adminupdatefile) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): looking to replace: %s", __FUNCTION__, __LINE__, _options.adminupdatefile);
- if (!radius_getnextattr(pack, &attr,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_CONFIG,
- 0, &offset)) {
- char template[] = "/tmp/hs.conf.XXXXXX";
- char * hs_conf = _options.adminupdatefile;
- /*
- * We have configurations in the administrative-user session.
- * Save to a temporary file.
- */
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): using template temp file: %s", __FUNCTION__, __LINE__, template);
- int fd = mkstemp(template);
- if (fd > 0) {
- do {
- if (safe_write(fd, attr->v.t, attr->l - 2) < 0 || safe_write(fd, "\n", 1) < 0) {
- syslog(LOG_ERR, "%s: adminupdatefile", strerror(errno));
- break;
- }
- }
- while (!radius_getnextattr(pack, &attr,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_CONFIG,
- 0, &offset));
- /*
- * Check to see if this file is different from the chilli/hs.conf
- */
- {
- int oldfd = open(hs_conf, O_RDONLY);
- if (fd > 0) {
- lseek(fd, SEEK_SET, 0);
- int differ = (oldfd > 0) ? 0 : 1;
- char b1[100], b2[100];
- ssize_t r1, r2;
- if (!differ) {
- do {
- r1 = safe_read(fd, b1, sizeof(b1));
- r2 = safe_read(oldfd, b2, sizeof(b2));
- if (r1 != r2 || strncmp(b1, b2, r1))
- differ = 1;
- }
- while (!differ && r1 > 0 && r2 > 0);
- }
- if (oldfd) {
- safe_close(oldfd);
- oldfd=0;
- }
- if (differ) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Writing out new hs.conf file with administraive-user settings", __FUNCTION__, __LINE__);
- oldfd = open(hs_conf, O_RDWR | O_TRUNC | O_CREAT, 0644);
- if (fd > 0 && oldfd > 0) {
- lseek(fd, SEEK_SET, 0);
- while ((r1 = safe_read(fd, b1, sizeof(b1))) > 0 &&
- safe_write(oldfd, b1, r1) > 0);
- safe_close(oldfd); oldfd=0;
- do_interval = 1;
- }
- }
- }
- if (oldfd > 0) safe_close(oldfd);
- }
- /* unlink(hs_temp); */
- safe_close(fd);
- }
- }
- }
- if (!admin_session.s_state.authenticated) {
- admin_session.s_state.authenticated = 1;
- acct_req(ACCT_USER, &admin_session, RADIUS_STATUS_TYPE_START);
- }
- /* reset these values to zero */
- admin_session.s_params.idletimeout = 0;
- admin_session.s_params.sessionterminatetime = 0;
- /* should instead honor this with a re-auth (see interval) */
- admin_session.s_params.sessiontimeout = 0;
- return 0;
- }
- int cb_radius_acct_conf(struct radius_t *radius,
- struct radius_packet_t *pack,
- struct radius_packet_t *pack_req, void *cbp) {
- struct app_conn_t *appconn = (struct app_conn_t*) cbp;
- if (!appconn) {
- syslog(LOG_ERR,"No peer protocol defined");
- return 0;
- }
- if (!pack) /* Timeout */
- return 0;
- config_radius_session(&appconn->s_params, pack, appconn, 1);
- return 0;
- }
- /*********************************************************
- * radius callback functions (response from radius server)
- *********************************************************/
- /* Radius callback when access accept/reject/challenge has been received */
- int cb_radius_auth_conf(struct radius_t *radius,
- struct radius_packet_t *pack,
- struct radius_packet_t *pack_req, void *cbp) {
- struct radius_attr_t *hisipattr = NULL;
- struct radius_attr_t *lmntattr = NULL;
- struct radius_attr_t *sendattr = NULL;
- struct radius_attr_t *recvattr = NULL;
- struct radius_attr_t *succattr = NULL;
- struct radius_attr_t *stateattr = NULL;
- struct radius_attr_t *classattr = NULL;
- struct radius_attr_t *uidattr = NULL;
- #ifdef ENABLE_RADPROXY
- int instance = 0;
- struct radius_attr_t *policyattr = NULL;
- struct radius_attr_t *typesattr = NULL;
- struct radius_attr_t *eapattr = NULL;
- #endif
- int force_ip = 0;
- struct in_addr hisip;
- struct in_addr hismask;
- struct app_conn_t *appconn = (struct app_conn_t*) cbp;
- struct dhcp_conn_t *dhcpconn = NULL;
- if (!appconn) {
- syslog(LOG_ERR,"No peer protocol defined");
- return 0;
- }
- dhcpconn = (struct dhcp_conn_t *)appconn->dnlink;
- /* Initialise */
- appconn->s_state.redir.statelen = 0;
- hisip.s_addr = hismask.s_addr = 0;
- #ifdef ENABLE_RADPROXY
- appconn->challen = 0;
- appconn->sendlen = 0;
- appconn->recvlen = 0;
- appconn->lmntlen = 0;
- #endif
- if (!pack) { /* Timeout */
- syslog(LOG_ERR, "RADIUS request id=%d timed out for session %s",
- pack_req ? pack_req->id : -1,
- appconn->s_state.sessionid);
- if (_options.noradallow) {
- session_param_defaults(&appconn->s_params);
- return upprot_getip(appconn, &appconn->reqip, 0);
- }
- return dnprot_reject(appconn);
- }
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Received RADIUS response id=%d", __FUNCTION__, __LINE__, pack->id);
- #endif
- /* Framed IP address (Optional) */
- if (!radius_getattr(pack, &hisipattr, RADIUS_ATTR_FRAMED_IP_ADDRESS, 0, 0, 0)
- #ifdef ENABLE_DHCPRADIUS
- || !radius_getattr(pack, &hisipattr,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_DHCP_IP_ADDRESS, 0)
- #endif
- ) {
- if ((hisipattr->l-2) != sizeof(struct in_addr)) {
- syslog(LOG_ERR, "Wrong length of framed IP address");
- return dnprot_reject(appconn);
- }
- force_ip = 1;
- hisip.s_addr = hisipattr->v.i;
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Framed IP address set to: %s", __FUNCTION__, __LINE__, inet_ntoa(hisip));
- if (!radius_getattr(pack, &hisipattr, RADIUS_ATTR_FRAMED_IP_NETMASK, 0, 0, 0)
- #ifdef ENABLE_DHCPRADIUS
- || !radius_getattr(pack, &hisipattr,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_DHCP_IP_NETMASK, 0)
- #endif
- ) {
- if ((hisipattr->l-2) != sizeof(struct in_addr)) {
- syslog(LOG_ERR, "Wrong length of framed IP netmask");
- return dnprot_reject(appconn);
- }
- hismask.s_addr = hisipattr->v.i;
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Framed IP netmask set to: %s", __FUNCTION__, __LINE__, inet_ntoa(hismask));
- }
- }
- else {
- hisip.s_addr = appconn->reqip.s_addr;
- }
- if (force_ip) {
- if (appconn->uplink) {
- struct ippoolm_t *ipm = (struct ippoolm_t *)appconn->uplink;
- if (hisip.s_addr) {
- /*
- * Force the assigment of an IP address.
- */
- if (ipm->addr.s_addr != hisip.s_addr) {
- uint8_t hwaddr[sizeof(dhcpconn->hismac)];
- memcpy(hwaddr, dhcpconn->hismac, sizeof(hwaddr));
- if (_options.debug) {
- syslog(LOG_DEBUG, "%s(%d): Old ip address freed %s", __FUNCTION__, __LINE__, inet_ntoa(ipm->addr));
- syslog(LOG_DEBUG, "%s(%d): Resetting ip address to %s", __FUNCTION__, __LINE__, inet_ntoa(hisip));
- }
- dhcp_freeconn(dhcpconn, 0);
- dhcp_newconn(dhcp, &dhcpconn, hwaddr);
- appconn->dnprot = DNPROT_MAC;
- appconn->authtype = PAP_PASSWORD;
- dhcpconn->authstate = DHCP_AUTH_DNAT;
- ipm = 0;
- }
- }
- }
- }
- #ifdef ENABLE_DHCPRADIUS
- if (_options.dhcpradius) {
- struct radius_attr_t *attr = NULL;
- if (dhcpconn) {
- if (!radius_getattr(pack, &attr,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_DHCP_SERVER_NAME, 0)) {
- memcpy(dhcpconn->dhcp_opts.sname, attr->v.t, attr->l-2);
- }
- if (!radius_getattr(pack, &attr,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_DHCP_FILENAME, 0)) {
- memcpy(dhcpconn->dhcp_opts.file, attr->v.t, attr->l-2);
- }
- if (!radius_getattr(pack, &attr,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_DHCP_OPTION, 0)) {
- memcpy(dhcpconn->dhcp_opts.options, attr->v.t,
- dhcpconn->dhcp_opts.option_length = attr->l-2);
- }
- if (!radius_getattr(pack, &attr,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_DHCP_DNS1, 0)) {
- if ((attr->l-2) == sizeof(struct in_addr)) {
- appconn->dns1.s_addr = attr->v.i;
- dhcpconn->dns1.s_addr = attr->v.i;
- }
- }
- if (!radius_getattr(pack, &attr,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_DHCP_DNS2, 0)) {
- if ((attr->l-2) == sizeof(struct in_addr)) {
- appconn->dns2.s_addr = attr->v.i;
- dhcpconn->dns2.s_addr = attr->v.i;
- }
- }
- if (!radius_getattr(pack, &attr,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_DHCP_GATEWAY, 0)) {
- if ((attr->l-2) == sizeof(struct in_addr)) {
- appconn->ourip.s_addr = attr->v.i;
- dhcpconn->ourip.s_addr = attr->v.i;
- }
- }
- if (!radius_getattr(pack, &attr,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_DHCP_DOMAIN, 0)) {
- if (attr->l-2 < DHCP_DOMAIN_LEN) {
- strncpy(dhcpconn->domain, (char *)attr->v.t, attr->l-2);
- dhcpconn->domain[attr->l-2]=0;
- }
- }
- }
- }
- #endif
- /* ACCESS-REJECT */
- if (pack->code == RADIUS_CODE_ACCESS_REJECT) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Received RADIUS Access-Reject", __FUNCTION__, __LINE__);
- config_radius_session(&appconn->s_params, pack, appconn, 0); /*XXX*/
- return dnprot_reject(appconn);
- }
- /* Get State */
- if (!radius_getattr(pack, &stateattr, RADIUS_ATTR_STATE, 0, 0, 0)) {
- appconn->s_state.redir.statelen = stateattr->l-2;
- memcpy(appconn->s_state.redir.statebuf, stateattr->v.t, stateattr->l-2);
- }
- #ifdef ENABLE_RADPROXY
- /* ACCESS-CHALLENGE */
- if (pack->code == RADIUS_CODE_ACCESS_CHALLENGE) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Received RADIUS Access-Challenge", __FUNCTION__, __LINE__);
- /* Get EAP message */
- appconn->challen = 0;
- do {
- eapattr=NULL;
- if (!radius_getattr(pack, &eapattr, RADIUS_ATTR_EAP_MESSAGE, 0, 0, instance++)) {
- if ((appconn->challen + eapattr->l-2) > MAX_EAP_LEN) {
- syslog(LOG_INFO, "EAP message too long %zu %d",
- appconn->challen, (int) eapattr->l-2);
- return dnprot_reject(appconn);
- }
- memcpy(appconn->chal+appconn->challen, eapattr->v.t, eapattr->l-2);
- appconn->challen += eapattr->l-2;
- }
- } while (eapattr);
- if (!appconn->challen) {
- syslog(LOG_INFO, "No EAP message found");
- return dnprot_reject(appconn);
- }
- return dnprot_challenge(appconn);
- }
- #endif
- /* ACCESS-ACCEPT */
- if (pack->code != RADIUS_CODE_ACCESS_ACCEPT) {
- syslog(LOG_ERR, "Unknown RADIUS code");
- return dnprot_reject(appconn);
- }
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Received RADIUS Access-Accept", __FUNCTION__, __LINE__);
- #endif
- if (!radius_getattr(pack, &uidattr, RADIUS_ATTR_USER_NAME, 0, 0, 0)) {
- if (uidattr->l-2 < USERNAMESIZE) {
- memcpy(appconn->s_state.redir.username,
- (char *)uidattr->v.t, uidattr->l-2);
- appconn->s_state.redir.username[uidattr->l-2]=0;
- }
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Received User-Name override from RADIUS Access-Accept: %s", __FUNCTION__, __LINE__, appconn->s_state.redir.username);
- #endif
- }
- /* Class */
- if (!radius_getattr(pack, &classattr, RADIUS_ATTR_CLASS, 0, 0, 0)) {
- appconn->s_state.redir.classlen = classattr->l-2;
- memcpy(appconn->s_state.redir.classbuf, classattr->v.t, classattr->l-2);
- /*syslog("!!!! CLASSLEN = %d !!!!", appconn->s_state.redir.classlen);*/
- }
- else {
- /*syslog("!!!! RESET CLASSLEN !!!!");*/
- appconn->s_state.redir.classlen = 0;
- }
- config_radius_session(&appconn->s_params, pack, appconn, 0);
- if (appconn->is_adminsession) {
- /* for the admin session */
- return chilliauth_cb(radius, pack, pack_req, cbp);
- }
- if (appconn->s_params.sessionterminatetime) {
- if (mainclock_rtdiff(appconn->s_params.sessionterminatetime) > 0) {
- syslog(LOG_WARNING, "WISPr-Session-Terminate-Time in the past received, rejecting");
- return dnprot_reject(appconn);
- }
- }
- #ifdef ENABLE_RADPROXY
- /* EAP Message */
- appconn->challen = 0;
- do {
- eapattr=NULL;
- if (!radius_getattr(pack, &eapattr, RADIUS_ATTR_EAP_MESSAGE, 0, 0,
- instance++)) {
- if ((appconn->challen + eapattr->l-2) > MAX_EAP_LEN) {
- syslog(LOG_INFO, "EAP message too long %zu %d",
- appconn->challen, (int) eapattr->l-2);
- return dnprot_reject(appconn);
- }
- memcpy(appconn->chal + appconn->challen,
- eapattr->v.t, eapattr->l-2);
- appconn->challen += eapattr->l-2;
- }
- } while (eapattr);
- /* Get sendkey */
- if (!radius_getattr(pack, &sendattr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_MS,
- RADIUS_ATTR_MS_MPPE_SEND_KEY, 0)) {
- if (radius_keydecode(radius, appconn->sendkey, RADIUS_ATTR_VLEN, &appconn->sendlen,
- (uint8_t *)&sendattr->v.t, sendattr->l-2,
- pack_req->authenticator,
- radius->secret, radius->secretlen)) {
- syslog(LOG_ERR, "radius_keydecode() failed!");
- return dnprot_reject(appconn);
- }
- }
- /* Get recvkey */
- if (!radius_getattr(pack, &recvattr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_MS,
- RADIUS_ATTR_MS_MPPE_RECV_KEY, 0)) {
- if (radius_keydecode(radius, appconn->recvkey, RADIUS_ATTR_VLEN, &appconn->recvlen,
- (uint8_t *)&recvattr->v.t, recvattr->l-2,
- pack_req->authenticator,
- radius->secret, radius->secretlen) ) {
- syslog(LOG_ERR, "radius_keydecode() failed!");
- return dnprot_reject(appconn);
- }
- }
- /* Get LMNT keys */
- if (!radius_getattr(pack, &lmntattr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_MS,
- RADIUS_ATTR_MS_CHAP_MPPE_KEYS, 0)) {
- /* TODO: Check length of vendor attributes */
- if (radius_pwdecode(radius, appconn->lmntkeys, RADIUS_MPPEKEYSSIZE,
- &appconn->lmntlen, (uint8_t *)&lmntattr->v.t,
- lmntattr->l-2, pack_req->authenticator,
- radius->secret, radius->secretlen)) {
- syslog(LOG_ERR, "radius_pwdecode() failed");
- return dnprot_reject(appconn);
- }
- }
- /* Get encryption policy */
- if (!radius_getattr(pack, &policyattr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_MS,
- RADIUS_ATTR_MS_MPPE_ENCRYPTION_POLICY, 0)) {
- appconn->policy = ntohl(policyattr->v.i);
- }
- /* Get encryption types */
- if (!radius_getattr(pack, &typesattr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_MS,
- RADIUS_ATTR_MS_MPPE_ENCRYPTION_TYPES, 0)) {
- appconn->types = ntohl(typesattr->v.i);
- }
- /* Get MS_Chap_v2 SUCCESS */
- if (!radius_getattr(pack, &succattr, RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_MS,
- RADIUS_ATTR_MS_CHAP2_SUCCESS, 0)) {
- if ((succattr->l-5) != MS2SUCCSIZE) {
- syslog(LOG_ERR, "Wrong length of MS-CHAP2 success: %d", succattr->l-5);
- return dnprot_reject(appconn);
- }
- memcpy(appconn->ms2succ, ((void*)&succattr->v.t)+3, MS2SUCCSIZE);
- }
- #endif
- switch(appconn->authtype) {
- case PAP_PASSWORD:
- break;
- #ifdef ENABLE_RADPROXY
- case EAP_MESSAGE:
- if (!appconn->challen) {
- syslog(LOG_INFO, "No EAP message found");
- return dnprot_reject(appconn);
- }
- break;
- #endif
- case CHAP_DIGEST_MD5:
- break;
- case CHAP_MICROSOFT:
- if (!lmntattr) {
- syslog(LOG_INFO, "No MPPE keys found");
- return dnprot_reject(appconn);
- }
- if (!succattr) {
- syslog(LOG_ERR, "No MS-CHAP2 success found");
- return dnprot_reject(appconn);
- }
- break;
- case CHAP_MICROSOFT_V2:
- if (!sendattr) {
- syslog(LOG_INFO, "No MPPE sendkey found");
- return dnprot_reject(appconn);
- }
- if (!recvattr) {
- syslog(LOG_INFO, "No MPPE recvkey found");
- return dnprot_reject(appconn);
- }
- break;
- default:
- syslog(LOG_ERR, "Unknown authtype");
- return dnprot_reject(appconn);
- }
- return upprot_getip(appconn, &hisip, &hismask);
- }
- #ifdef ENABLE_COA
- /* Radius callback when coa or disconnect request has been received */
- int cb_radius_coa_ind(struct radius_t *radius, struct radius_packet_t *pack,
- struct sockaddr_in *peer) {
- struct app_conn_t *appconn;
- struct radius_attr_t *uattr = NULL;
- struct radius_attr_t *sattr = NULL;
- struct radius_packet_t radius_pack;
- int authorize = 0;
- int found = 0;
- int iscoa = 0;
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Received coa or disconnect request\n", __FUNCTION__, __LINE__);
- #endif
- if (pack->code != RADIUS_CODE_DISCONNECT_REQUEST &&
- pack->code != RADIUS_CODE_COA_REQUEST) {
- syslog(LOG_ERR, "Radius packet not supported: %d,\n", pack->code);
- return -1;
- }
- iscoa = pack->code == RADIUS_CODE_COA_REQUEST;
- /* Get username */
- if (radius_getattr(pack, &uattr, RADIUS_ATTR_USER_NAME, 0, 0, 0)) {
- syslog(LOG_WARNING, "Username must be included in disconnect request");
- return -1;
- }
- if (!radius_getattr(pack, &sattr, RADIUS_ATTR_ACCT_SESSION_ID, 0, 0, 0))
- if (_options.debug) {
- syslog(LOG_DEBUG, "%s(%d): Session-id present in disconnect. Only disconnecting that session\n", __FUNCTION__, __LINE__);
- syslog(LOG_DEBUG, "%s(%d): Looking for session [username=%.*s,sessionid=%.*s]", __FUNCTION__, __LINE__,
- uattr->l-2, uattr->v.t, sattr ? sattr->l-2 : 3,
- sattr ? (char*)sattr->v.t : "all");
- }
- for (appconn = firstusedconn; appconn; appconn = appconn->next) {
- if (!appconn->inuse) { syslog(LOG_ERR, "Connection with inuse == 0!"); }
- if (
- (strlen(appconn->s_state.redir.username) == uattr->l-2 &&
- !memcmp(appconn->s_state.redir.username, uattr->v.t, uattr->l-2)) &&
- (!sattr ||
- (strlen(appconn->s_state.sessionid) == sattr->l-2 &&
- !strncasecmp(appconn->s_state.sessionid, (char*)sattr->v.t, sattr->l-2)))) {
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Found session %s", __FUNCTION__, __LINE__, appconn->s_state.sessionid);
- #endif
- if (iscoa) {
- struct radius_attr_t *attr = NULL;
- /* Session state */
- if (!radius_getattr(pack, &attr,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- RADIUS_VENDOR_COOVACHILLI,
- RADIUS_ATTR_COOVACHILLI_SESSION_STATE, 0)) {
- uint32_t v = ntohl(attr->v.i);
- switch (v) {
- case RADIUS_VALUE_COOVACHILLI_SESSION_AUTH:
- if (!appconn->s_state.authenticated)
- authorize = 1;
- break;
- case RADIUS_VALUE_COOVACHILLI_SESSION_NOAUTH:
- if (appconn->s_state.authenticated)
- terminate_appconn(appconn, RADIUS_TERMINATE_CAUSE_USER_REQUEST);
- break;
- }
- }
- } else {
- terminate_appconn(appconn, RADIUS_TERMINATE_CAUSE_ADMIN_RESET);
- }
- config_radius_session(&appconn->s_params, pack, appconn, 0);
- if (authorize)
- dnprot_accept(appconn);
- found = 1;
- }
- }
- if (found) {
- if (radius_default_pack(radius, &radius_pack,
- iscoa ? RADIUS_CODE_COA_ACK : RADIUS_CODE_DISCONNECT_ACK)) {
- syslog(LOG_ERR, "radius_default_pack() failed");
- return -1;
- }
- }
- else {
- if (radius_default_pack(radius, &radius_pack,
- iscoa ? RADIUS_CODE_COA_NAK : RADIUS_CODE_DISCONNECT_NAK)) {
- syslog(LOG_ERR, "radius_default_pack() failed");
- return -1;
- }
- }
- radius_pack.id = pack->id;
- (void) radius_coaresp(radius, &radius_pack, peer, pack->authenticator);
- return 0;
- }
- #endif
- /***********************************************************
- *
- * dhcp callback functions
- *
- ***********************************************************/
- /* DHCP callback for allocating new IP address */
- /* In the case of WPA it is allready allocated,
- * for UAM address is allocated before authentication */
- int cb_dhcp_request(struct dhcp_conn_t *conn, struct in_addr *addr,
- uint8_t *dhcp_pkt, size_t dhcp_len) {
- struct app_conn_t *appconn = conn->peer;
- struct ippoolm_t *ipm = 0;
- char domacauth = (char) _options.macauth;
- char allocate = 1;
- #if(_debug_)
- syslog(LOG_DEBUG, "%s(%d): DHCP request for IP address %s", __FUNCTION__, __LINE__,
- addr ? inet_ntoa(*addr) : "n/a");
- #endif
- if (!appconn) {
- syslog(LOG_ERR, "Peer protocol not defined");
- return -1;
- }
- #ifdef ENABLE_UAMANYIP
- /* if uamanyip is on we have to filter out which ip's are allowed */
- if (_options.uamanyip && addr && addr->s_addr) {
- if (addr->s_addr == _options.uamlisten.s_addr) {
- return -1;
- }
- if (_options.uamanyipex_addr.s_addr &&
- (addr->s_addr & _options.uamanyipex_mask.s_addr) ==
- _options.uamanyipex_addr.s_addr) {
- return -1;
- }
- if ((addr->s_addr & ipv4ll_mask.s_addr) == ipv4ll_ip.s_addr) {
- /* clients with an IPv4LL ip normally have no default gw assigned, rendering uamanyip useless
- They must rather get a proper dynamic ip via dhcp */
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): IPv4LL/APIPA address requested, ignoring %s", __FUNCTION__, __LINE__,
- inet_ntoa(*addr));
- return -1;
- }
- }
- #endif
- /* Save for MAC auth later */
- appconn->reqip.s_addr = addr ? addr->s_addr : 0;
- if (appconn->uplink) {
- /*
- * IP Address is already known and allocated.
- */
- ipm = (struct ippoolm_t*) appconn->uplink;
- } else {
- if ( ! conn->is_reserved) {
- if ((_options.macoklen) &&
- (appconn->dnprot == DNPROT_DHCP_NONE) &&
- !maccmp(conn->hismac)) {
- /*
- * When using macallowed option, and hismac matches.
- */
- appconn->dnprot = DNPROT_MAC;
- if (_options.macallowlocal) {
- char mac[MACSTRLEN+1];
- snprintf(mac, sizeof(mac), MAC_FMT, MAC_ARG(conn->hismac));
- strlcpy(appconn->s_state.redir.username, mac, USERNAMESIZE);
- if (_options.macsuffix) {
- size_t ulen = strlen(appconn->s_state.redir.username);
- strlcpy(appconn->s_state.redir.username + ulen,
- _options.macsuffix, USERNAMESIZE - ulen);
- }
- /*
- * Local MAC allowed list, authenticate without RADIUS.
- */
- upprot_getip(appconn, &appconn->reqip, 0);
- syslog(LOG_INFO, "Granted MAC=%s with IP=%s access without radius auth",
- mac, inet_ntoa(appconn->hisip));
- ipm = (struct ippoolm_t*) appconn->uplink;
- domacauth = 0;
- } else {
- /*
- * Otherwise, authenticate with RADIUS.
- */
- auth_radius(appconn, 0, 0, dhcp_pkt, dhcp_len);
- allocate = !_options.strictmacauth;
- domacauth = 0;
- }
- } else if ((_options.macauth) &&
- (appconn->dnprot == DNPROT_DHCP_NONE)) {
- /*
- * Using macauth option to authenticate via RADIUS.
- */
- appconn->dnprot = DNPROT_MAC;
- auth_radius(appconn, 0, 0, dhcp_pkt, dhcp_len);
- allocate = !_options.strictmacauth;
- domacauth = 0;
- }
- }
- }
- if (!ipm) {
- if (!allocate)
- return -1;
- if (appconn->dnprot != DNPROT_DHCP_NONE && appconn->hisip.s_addr) {
- syslog(LOG_WARNING, "Requested IP address when already allocated (hisip %s)",
- inet_ntoa(appconn->hisip));
- appconn->reqip.s_addr = appconn->hisip.s_addr;
- }
- /* Allocate dynamic IP address */
- /* XXX if (ippool_newip(ippool, &ipm, &appconn->reqip, 0)) {*/
- if (newip(&ipm, &appconn->reqip, conn->hismac)) {
- syslog(LOG_ERR, "Failed allocate dynamic IP address");
- return -1;
- }
- appconn->hisip.s_addr = ipm->addr.s_addr;
- appconn->hismask.s_addr = _options.mask.s_addr;
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Client MAC="MAC_FMT" assigned IP %s" , __FUNCTION__, __LINE__,
- MAC_ARG(conn->hismac), inet_ntoa(appconn->hisip));
- #ifdef ENABLE_MODULES
- { int i;
- for (i=0; i < MAX_MODULES; i++) {
- if (!_options.modules[i].name[0]) break;
- if (_options.modules[i].ctx) {
- struct chilli_module *m =
- (struct chilli_module *)_options.modules[i].ctx;
- if (m->dhcp_connect)
- m->dhcp_connect(appconn, conn);
- }
- }
- }
- #endif
- /* TODO: Too many "listen" and "our" addresses hanging around */
- if (!appconn->ourip.s_addr)
- appconn->ourip.s_addr = _options.dhcplisten.s_addr;
- appconn->uplink = ipm;
- ipm->peer = appconn;
- #ifdef ENABLE_GARDENACCOUNTING
- if (_options.uamgardendata) {
- acct_req(ACCT_GARDEN, appconn, RADIUS_STATUS_TYPE_START);
- }
- #endif
- #ifdef ENABLE_UAMANYIP
- if (chilli_assign_snat(appconn, 0) != 0) {
- return -1;
- }
- #endif
- }
- if (ipm) {
- dhcp_set_addrs(conn,
- &ipm->addr, &_options.mask,
- &appconn->ourip, &appconn->mask,
- &_options.dns1, &_options.dns2);
- }
- if (!appconn->s_state.authenticated) {
- if (domacauth) {
- auth_radius(appconn, 0, 0, dhcp_pkt, dhcp_len);
- }
- /* if not already authenticated, ensure DNAT authstate */
- #ifdef ENABLE_LAYER3
- if (!_options.layer3)
- #endif
- conn->authstate = DHCP_AUTH_DNAT;
- }
- /* If IP was requested before authentication it was UAM */
- if (appconn->dnprot == DNPROT_DHCP_NONE)
- appconn->dnprot = DNPROT_UAM;
- if (_options.dhcpnotidle)
- appconn->s_state.last_up_time = mainclock.tv_sec;
- return 0;
- }
- int chilli_connect(struct app_conn_t **appconn, struct dhcp_conn_t *conn) {
- struct app_conn_t *aconn;
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): New Chilli Connection", __FUNCTION__, __LINE__);
- #endif
- /* Allocate new application connection */
- if (chilli_new_conn(appconn)) {
- syslog(LOG_ERR, "Failed to allocate connection");
- return -1;
- }
- aconn = *appconn;
- aconn->dnlink = conn;
- aconn->dnprot = DNPROT_DHCP_NONE;
- aconn->net.s_addr = _options.net.s_addr;
- aconn->mask.s_addr = _options.mask.s_addr;
- aconn->dns1.s_addr = _options.dns1.s_addr;
- aconn->dns2.s_addr = _options.dns2.s_addr;
- if (conn) {
- memcpy(aconn->hismac, conn->hismac, PKT_ETH_ALEN);
- }
- set_sessionid(aconn, 1);
- app_conn_set_idx(aconn, conn);
- #ifdef ENABLE_BINSTATFILE
- if (_options.statusfilesave)
- printstatus();
- #endif
- return 0;
- }
- /* DHCP callback for establishing new connection */
- int cb_dhcp_connect(struct dhcp_conn_t *conn) {
- struct app_conn_t *appconn;
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): New DHCP request from MAC="MAC_FMT, __FUNCTION__, __LINE__,
- MAC_ARG(conn->hismac));
- if (chilli_connect(&appconn, conn))
- return 0;
- conn->peer = appconn;
- conn->authstate = DHCP_AUTH_NONE; /* TODO: Not yet authenticated */
- if (_options.macup) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Calling MAC up script: %s", __FUNCTION__, __LINE__, _options.macup);
- runscript(appconn, _options.macup, 0, 0);
- }
- return 0;
- }
- #ifdef ENABLE_LAYER3
- struct app_conn_t * chilli_connect_layer3(struct in_addr *src, struct dhcp_conn_t *conn) {
- struct app_conn_t *appconn = 0;
- struct ippoolm_t *ipm = 0;
- if (ippool_getip(ippool, &ipm, src)) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): New Layer3 %s", __FUNCTION__, __LINE__, inet_ntoa(*src));
- if (ippool_newip(ippool, &ipm, src, 1)) {
- if (ippool_newip(ippool, &ipm, src, 0)) {
- syslog(LOG_ERR, "Failed to allocate either static or dynamic IP address");
- return 0;
- }
- }
- }
- if (!ipm) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): unknown ip", __FUNCTION__, __LINE__);
- return 0;
- }
- if ((appconn = (struct app_conn_t *)ipm->peer) == NULL) {
- if (chilli_getconn(&appconn, src->s_addr, 0, 0)) {
- if (chilli_connect(&appconn, conn)) {
- syslog(LOG_ERR, "chilli_connect()");
- return 0;
- }
- }
- }
- appconn->s_state.last_up_time = mainclock_now();
- appconn->hisip.s_addr = src->s_addr;
- appconn->hismask.s_addr = _options.mask.s_addr;
- appconn->dnprot = DNPROT_LAYER3;
- appconn->uplink = ipm;
- ipm->peer = appconn;
- return appconn;
- }
- #endif
- #ifdef ENABLE_CHILLIQUERY
- static char *state2name(int authstate) {
- switch(authstate) {
- case DHCP_AUTH_NONE: return "none";
- case DHCP_AUTH_DROP: return "drop";
- case DHCP_AUTH_PASS: return "pass";
- case DHCP_AUTH_DNAT: return "dnat";
- case DHCP_AUTH_SPLASH: return "splash";
- #ifdef ENABLE_LAYER3
- case DHCP_AUTH_ROUTER: return "layer2";
- #endif
- default: return "unknown";
- }
- }
- int chilli_getinfo(struct app_conn_t *appconn, bstring b, int fmt) {
- uint32_t sessiontime = 0;
- uint32_t idletime = 0;
- if (appconn->s_state.authenticated) {
- sessiontime = mainclock_diffu(appconn->s_state.start_time);
- idletime = mainclock_diffu(appconn->s_state.last_up_time);
- }
- switch(fmt) {
- #ifdef ENABLE_JSON
- case LIST_JSON_FMT:
- if (appconn->s_state.authenticated)
- session_json_fmt(&appconn->s_state, &appconn->s_params, b, 0);
- break;
- #endif
- default:
- {
- bstring tmp = bfromcstr("");
- /* adding: session-id auth-state user-name */
- bassignformat(tmp, " %.*s %d %.*s",
- appconn->s_state.sessionid[0] ? strlen(appconn->s_state.sessionid) : 1,
- appconn->s_state.sessionid[0] ? appconn->s_state.sessionid : "-",
- appconn->s_state.authenticated,
- appconn->s_state.redir.username[0] ? strlen(appconn->s_state.redir.username) : 1,
- appconn->s_state.redir.username[0] ? appconn->s_state.redir.username : "-");
- bconcat(b, tmp);
- /* adding: session-time/session-timeout idle-time/idle-timeout */
- bassignformat(tmp, " %d/%d %d/%d",
- sessiontime, (int)appconn->s_params.sessiontimeout,
- idletime, (int)appconn->s_params.idletimeout);
- bconcat(b, tmp);
- /* adding: input-octets/max-input-octets */
- #ifdef ENABLE_GARDENACCOUNTING
- if (_options.uamgardendata && _options.uamotherdata)
- bassignformat(tmp, " %lld/%lld/%lld/%lld",
- appconn->s_state.input_octets,
- appconn->s_params.maxinputoctets,
- appconn->s_state.garden_input_octets,
- appconn->s_state.other_input_octets);
- else if (_options.uamgardendata)
- bassignformat(tmp, " %lld/%lld/%lld",
- appconn->s_state.input_octets,
- appconn->s_params.maxinputoctets,
- appconn->s_state.garden_input_octets);
- else
- #endif
- bassignformat(tmp, " %lld/%lld",
- appconn->s_state.input_octets,
- appconn->s_params.maxinputoctets);
- bconcat(b, tmp);
- /* adding: output-octets/max-output-octets */
- #ifdef ENABLE_GARDENACCOUNTING
- if (_options.uamgardendata && _options.uamotherdata)
- bassignformat(tmp, " %lld/%lld/%lld/%lld",
- appconn->s_state.output_octets,
- appconn->s_params.maxoutputoctets,
- appconn->s_state.garden_output_octets,
- appconn->s_state.other_output_octets);
- else if (_options.uamgardendata)
- bassignformat(tmp, " %lld/%lld/%lld",
- appconn->s_state.output_octets,
- appconn->s_params.maxoutputoctets,
- appconn->s_state.garden_output_octets);
- else
- #endif
- bassignformat(tmp, " %lld/%lld",
- appconn->s_state.output_octets,
- appconn->s_params.maxoutputoctets);
- bconcat(b, tmp);
- /* adding: max-total-octets option-swapoctets */
- bassignformat(tmp, " %lld %d",
- appconn->s_params.maxtotaloctets, _options.swapoctets);
- bconcat(b, tmp);
- #ifdef ENABLE_LEAKYBUCKET
- /* adding: max-bandwidth-up max-bandwidth-down */
- if (appconn->s_state.bucketupsize) {
- bassignformat(tmp, " %d%%/%lld",
- (int) (appconn->s_state.bucketup * 100 /
- appconn->s_state.bucketupsize),
- appconn->s_params.bandwidthmaxup);
- bconcat(b, tmp);
- } else
- #endif
- bcatcstr(b, " 0/0");
- #ifdef ENABLE_LEAKYBUCKET
- if (appconn->s_state.bucketdownsize) {
- bassignformat(tmp, " %d%%/%lld ",
- (int) (appconn->s_state.bucketdown * 100 /
- appconn->s_state.bucketdownsize),
- appconn->s_params.bandwidthmaxdown);
- bconcat(b, tmp);
- } else
- #endif
- bcatcstr(b, " 0/0 ");
- /* adding: original url */
- if (appconn->s_state.redir.userurl[0])
- bcatcstr(b, appconn->s_state.redir.userurl);
- else
- bcatcstr(b, "-");
- #ifdef ENABLE_IEEE8021Q
- /* adding: vlan, if one */
- if (_options.ieee8021q && appconn->s_state.tag8021q) {
- bassignformat(tmp, " vlan=%d",
- (int)ntohs(appconn->s_state.tag8021q &
- PKT_8021Q_MASK_VID));
- bconcat(b, tmp);
- } else {
- #endif
- #ifdef ENABLE_MULTILAN
- if (app_conn_idx(appconn)) {
- bassignformat(tmp, " vlan=%s",
- _options.moreif[app_conn_idx(appconn)-1].vlan ?
- _options.moreif[app_conn_idx(appconn)-1].vlan :
- _options.moreif[app_conn_idx(appconn)-1].dhcpif);
- } else {
- bassignformat(tmp, " vlan=%s", _options.vlan);
- }
- bconcat(b, tmp);
- #endif
- #ifdef ENABLE_IEEE8021Q
- }
- #endif
- #ifdef ENABLE_LOCATION
- if (appconn->s_state.location[0]) {
- bstring tmp2 = bfromcstr("");
- bcatcstr(b, " loc=");
- bassigncstr(tmp, appconn->s_state.location);
- redir_urlencode(tmp, tmp2);
- bconcat(b, tmp2);
- bdestroy(tmp2);
- }
- #endif
- bdestroy(tmp);
- }
- }
- return 0;
- }
- void chilli_print(bstring s, int listfmt,
- struct app_conn_t *appconn,
- struct dhcp_conn_t *conn) {
- if (!appconn && conn)
- appconn = (struct app_conn_t *)conn->peer;
- if (
- #ifdef ENABLE_LAYER3
- !_options.layer3 &&
- #endif
- (!appconn || !appconn->inuse)) {
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Can not print info about unused chilli connection", __FUNCTION__, __LINE__);
- #endif
- return;
- } else if (conn && !conn->inuse) {
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Can not print info about unused dhcp connection", __FUNCTION__, __LINE__);
- #endif
- return;
- } else {
- bstring b = bfromcstr("");
- bstring tmp = bfromcstr("");
- switch(listfmt) {
- #ifdef ENABLE_JSON
- case LIST_JSON_FMT:
- if ((conn && conn != dhcp->firstusedconn) ||
- (appconn && appconn != firstusedconn))
- bcatcstr(b, ",");
- bcatcstr(b, "{");
- if (appconn) {
- bcatcstr(b, "\"nasPort\":");
- bassignformat(tmp, "%d", appconn->unit);
- bconcat(b, tmp);
- bcatcstr(b, ",\"clientState\":");
- bassignformat(tmp, "%d", appconn->s_state.authenticated);
- bconcat(b, tmp);
- bcatcstr(b, ",\"ipAddress\":\"");
- bcatcstr(b, inet_ntoa(appconn->hisip));
- bcatcstr(b, "\"");
- }
- if (conn) {
- if (appconn) bcatcstr(b, ",");
- bcatcstr(b, "\"macAddress\":\"");
- bassignformat(tmp, MAC_FMT, MAC_ARG(conn->hismac));
- bconcat(b, tmp);
- bcatcstr(b, "\",\"dhcpState\":\"");
- bcatcstr(b, state2name(conn->authstate));
- bcatcstr(b, "\"");
- }
- if (appconn)
- chilli_getinfo(appconn, b, listfmt);
- bcatcstr(b, "}");
- break;
- #endif
- default:
- if (conn && !appconn)
- bassignformat(b, MAC_FMT" %s", MAC_ARG(conn->hismac),
- state2name(conn->authstate));
- else if (conn)
- bassignformat(b, MAC_FMT" %s %s", MAC_ARG(conn->hismac),
- inet_ntoa(conn->hisip), state2name(conn->authstate));
- else
- bassignformat(b, "%s", inet_ntoa(appconn->hisip));
- switch(listfmt) {
- case LIST_LONG_FMT:
- if (appconn)
- chilli_getinfo(appconn, b, listfmt);
- break;
- case LIST_SHORT_FMT:
- if (conn) {
- bassignformat(tmp, " %d/%d",
- mainclock_diff(conn->lasttime),
- dhcp->lease);
- bconcat(b, tmp);
- }
- break;
- }
- bcatcstr(b, "\n");
- break;
- }
- bconcat(s, b);
- bdestroy(b);
- bdestroy(tmp);
- }
- }
- #endif
- static void
- clear_appconn(struct app_conn_t *appconn) {
- appconn->s_params.bandwidthmaxup =
- appconn->s_params.bandwidthmaxdown =
- appconn->s_params.maxinputoctets =
- appconn->s_params.maxoutputoctets =
- appconn->s_params.maxtotaloctets =
- appconn->s_params.sessiontimeout = 0;
- appconn->s_params.idletimeout = 0;
- appconn->s_params.interim_interval = 0;
- appconn->s_params.sessionterminatetime = 0;
- }
- int terminate_appconn(struct app_conn_t *appconn, int terminate_cause) {
- if (appconn->s_state.authenticated == 1) {
- dnprot_terminate(appconn);
- appconn->s_state.terminate_cause = terminate_cause;
- #ifdef ENABLE_MODULES
- { int i;
- for (i=0; i < MAX_MODULES; i++) {
- if (!_options.modules[i].name[0]) break;
- if (_options.modules[i].ctx) {
- struct chilli_module *m =
- (struct chilli_module *)_options.modules[i].ctx;
- if (m->session_stop)
- m->session_stop(appconn);
- }
- }
- }
- #endif
- if (_options.condown && !(appconn->s_params.flags & NO_SCRIPT)) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Calling connection down script: %s\n", __FUNCTION__, __LINE__, _options.condown);
- runscript(appconn, _options.condown, 0, 0);
- }
- acct_req(ACCT_USER, appconn, RADIUS_STATUS_TYPE_STOP);
- clear_appconn(appconn);
- set_sessionid(appconn, 0);
- #ifdef ENABLE_STATFILE
- if (_options.statusfilesave)
- printstatus();
- #endif
- }
- return 0;
- }
- /* Callback when a dhcp connection is deleted */
- int cb_dhcp_disconnect(struct dhcp_conn_t *conn, int term_cause) {
- struct app_conn_t *appconn;
- syslog(LOG_INFO, "DHCP Released MAC="MAC_FMT" IP=%s",
- MAC_ARG(conn->hismac), inet_ntoa(conn->hisip));
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): DHCP connection removed", __FUNCTION__, __LINE__);
- if (!conn->peer) {
- /* No appconn allocated. Stop here */
- #ifdef ENABLE_BINSTATFILE
- if (_options.statusfilesave)
- printstatus();
- #endif
- return 0;
- }
- appconn = (struct app_conn_t*) conn->peer;
- return session_disconnect(appconn, conn, term_cause);
- }
- /* Callback for receiving messages from dhcp */
- int cb_dhcp_data_ind(struct dhcp_conn_t *conn, uint8_t *pack, size_t len) {
- struct app_conn_t *appconn = dhcp_get_appconn_pkt(conn, pkt_iphdr(pack), 0);
- struct pkt_ipphdr_t *ipph = pkt_ipphdr(pack);
- /*if (_options.debug)
- syslog(LOG_DEBUG, "cb_dhcp_data_ind. Packet received. DHCP authstate: %d\n",
- conn->authstate);*/
- #ifdef ENABLE_LEAKYBUCKET
- if (_options.scalewin && appconn && appconn->s_state.bucketup) {
- uint16_t win = appconn->s_state.bucketupsize -
- appconn->s_state.bucketup;
- //log_dbg("window scaling to %d", win);
- pkt_shape_tcpwin((struct pkt_iphdr_t *)ipph, win);
- }
- #endif
- if (!appconn) {
- #ifdef ENABLE_LAYER3
- if (_options.layer3) {
- struct ippoolm_t *ipm = 0;
- struct in_addr addr;
- addr.s_addr = ipph->saddr;
- if (!addr.s_addr) {
- return tun_encaps(tun, pack, len, 0);
- }
- if (ippool_getip(ippool, &ipm, &addr)) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): unknown IP address: %s", __FUNCTION__, __LINE__, inet_ntoa(addr));
- return -1;
- }
- appconn = ipm->peer;
- }
- if (!appconn)
- #endif
- {
- syslog(LOG_ERR, "No peer protocol defined");
- return -1;
- }
- }
- switch (appconn->dnprot) {
- case DNPROT_NULL:
- case DNPROT_DHCP_NONE:
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): NULL: %d", __FUNCTION__, __LINE__, appconn->dnprot);
- return -1;
- case DNPROT_UAM:
- case DNPROT_WPA:
- case DNPROT_MAC:
- #ifdef ENABLE_EAPOL
- case DNPROT_EAPOL:
- #endif
- #ifdef ENABLE_LAYER3
- case DNPROT_LAYER3:
- #endif
- break;
- default:
- syslog(LOG_ERR, "Unknown downlink protocol: %d", appconn->dnprot);
- break;
- }
- #ifdef ENABLE_UAMANYIP
- /**
- * packet is coming from an anyip client, therefore SNAT address
- * has been assigned from dynamic pool. So, let's do the SNAT here.
- */
- if (_options.uamanyip && appconn->natip.s_addr) {
- #if(_debug_ > 1)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): SNAT to: %s", __FUNCTION__, __LINE__, inet_ntoa(appconn->natip));
- #endif
- ipph->saddr = appconn->natip.s_addr;
- if (chksum((struct pkt_iphdr_t *) ipph) < 0)
- return 0;
- }
- #endif
- /*
- * If the ip dst is uamlisten and pdst is uamport we won't call leaky_bucket,
- * and we always send these packets through to the tun/tap interface (index 0)
- */
- if (ipph->daddr == _options.uamlisten.s_addr &&
- (ipph->dport == htons(_options.uamport)
- #ifdef ENABLE_UAMUIPORT
- || ipph->dport == htons(_options.uamuiport)
- #endif
- )) {
- return tun_encaps(tun, pack, len, 0);
- }
- if (chilli_acct_fromsub(appconn, ipph))
- return 0;
- return tun_encaps(tun, pack, len, appconn->s_params.routeidx);
- }
- int chilli_acct_fromsub(struct app_conn_t *appconn,
- struct pkt_ipphdr_t *ipph) {
- int len = ntohs(ipph->tot_len);
- #ifdef ENABLE_GARDENACCOUNTING
- char checked_garden = 0;
- #endif
- char is_garden = 0;
- char is_auth;
- char do_acct;
- #ifdef ENABLE_LEAKYBUCKET
- char do_bw;
- #endif
- is_auth = appconn->s_state.authenticated == 1;
- if (is_auth) {
- do_acct = is_auth;
- #ifdef ENABLE_LEAKYBUCKET
- do_bw = is_auth;
- #endif
- #ifdef ENABLE_AUTHEDALLOWED
- if (dhcp_garden_check_auth(dhcp, 0, appconn, ipph, 1)) {
- /*
- * Change to garden accounting.
- */
- if (_options.nousergardendata)
- is_garden = 1;
- #ifdef ENABLE_LEAKYBUCKET
- do_bw = 0;
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): !!!! Skipping leaky bucket because of authedallowed", __FUNCTION__, __LINE__);
- #endif
- }
- #endif
- if (_options.uamauthedallowed
- #ifdef ENABLE_LEAKYBUCKET
- && do_bw
- #endif
- ) {
- #ifdef ENABLE_GARDENACCOUNTING
- checked_garden = 1;
- #endif
- if (dhcp_garden_check(dhcp, 0, appconn, ipph, 1)) {
- /*
- * Garden accounting taken care of in dhcp_garden_check()
- */
- do_acct = 0;
- #ifdef ENABLE_LEAKYBUCKET
- do_bw = 0;
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): !!!! Skipping leaky bucket because of uamauthedallowed", __FUNCTION__, __LINE__);
- #endif
- }
- }
- #ifdef ENABLE_GARDENACCOUNTING
- if (_options.nousergardendata) {
- if (!checked_garden) {
- checked_garden = 1;
- if (dhcp_garden_check(dhcp, 0, appconn, ipph, 1)) {
- do_acct = 0;
- }
- }
- }
- #endif
- #ifdef ENABLE_LEAKYBUCKET
- #ifndef COUNT_UPLINK_DROP
- if (do_bw) {
- if (leaky_bucket(appconn, len, 0)) return 1;
- }
- #endif
- #endif
- if (do_acct) {
- if (is_garden) {
- #ifdef ENABLE_GARDENACCOUNTING
- if (_options.swapoctets) {
- appconn->s_state.garden_input_octets += len;
- if (admin_session.s_state.authenticated) {
- admin_session.s_state.garden_input_octets += len;
- }
- } else {
- appconn->s_state.garden_output_octets += len;
- if (admin_session.s_state.authenticated) {
- admin_session.s_state.garden_output_octets += len;
- }
- }
- #endif
- } else {
- if (_options.swapoctets) {
- appconn->s_state.input_packets++;
- appconn->s_state.input_octets += len;
- if (admin_session.s_state.authenticated) {
- admin_session.s_state.input_packets++;
- admin_session.s_state.input_octets += len;
- }
- } else {
- appconn->s_state.output_packets++;
- appconn->s_state.output_octets += len;
- if (admin_session.s_state.authenticated) {
- admin_session.s_state.output_packets++;
- admin_session.s_state.output_octets += len;
- }
- }
- }
- }
- #ifdef ENABLE_LEAKYBUCKET
- #ifdef COUNT_UPLINK_DROP
- if (do_bw) {
- if (leaky_bucket(appconn, len, 0)) return 1;
- }
- #endif
- #endif
- }
- appconn->s_state.last_time = mainclock.tv_sec;
- appconn->s_state.last_up_time = mainclock.tv_sec;
- return 0;
- }
- int chilli_acct_tosub(struct app_conn_t *appconn,
- struct pkt_ipphdr_t *ipph) {
- int len = ntohs(ipph->tot_len);
- #ifdef ENABLE_GARDENACCOUNTING
- char checked_garden = 0;
- #endif
- char is_garden = 0;
- char is_auth;
- char do_acct;
- #ifdef ENABLE_LEAKYBUCKET
- char do_bw;
- #endif
- is_auth = appconn->s_state.authenticated == 1;
- if (is_auth) {
- do_acct = is_auth;
- #ifdef ENABLE_LEAKYBUCKET
- do_bw = is_auth;
- #endif
- #ifdef ENABLE_AUTHEDALLOWED
- if (dhcp_garden_check_auth(dhcp, 0, appconn, ipph, 0)) {
- /*
- * Change to garden accounting.
- */
- if (_options.nousergardendata)
- is_garden = 1;
- #ifdef ENABLE_LEAKYBUCKET
- do_bw = 0;
- #endif
- }
- #endif
- if (_options.uamauthedallowed
- #ifdef ENABLE_LEAKYBUCKET
- && do_bw
- #endif
- ) {
- #ifdef ENABLE_GARDENACCOUNTING
- checked_garden = 1;
- #endif
- if (dhcp_garden_check(dhcp, 0, appconn, ipph, 0)) {
- /*
- * Garden accounting taken care of in dhcp_garden_check()
- */
- do_acct = 0;
- #ifdef ENABLE_LEAKYBUCKET
- do_bw = 0;
- #endif
- }
- }
- #ifdef ENABLE_GARDENACCOUNTING
- if (_options.nousergardendata) {
- if (!checked_garden) {
- checked_garden = 1;
- if (dhcp_garden_check(dhcp, 0, appconn, ipph, 0)) {
- do_acct = 0;
- }
- }
- }
- #endif
- #ifdef ENABLE_LEAKYBUCKET
- #ifndef COUNT_DOWNLINK_DROP
- if (do_bw) {
- if (leaky_bucket(appconn, 0, len)) return 1;
- }
- #endif
- #endif
- if (do_acct) {
- if (is_garden) {
- #ifdef ENABLE_GARDENACCOUNTING
- if (_options.swapoctets) {
- appconn->s_state.garden_output_octets += len;
- if (admin_session.s_state.authenticated) {
- admin_session.s_state.garden_output_octets += len;
- }
- } else {
- appconn->s_state.garden_input_octets += len;
- if (admin_session.s_state.authenticated) {
- admin_session.s_state.garden_input_octets += len;
- }
- }
- #endif
- } else {
- if (_options.swapoctets) {
- appconn->s_state.output_packets++;
- appconn->s_state.output_octets += len;
- if (admin_session.s_state.authenticated) {
- admin_session.s_state.output_packets++;
- admin_session.s_state.output_octets += len;
- }
- } else {
- appconn->s_state.input_packets++;
- appconn->s_state.input_octets += len;
- if (admin_session.s_state.authenticated) {
- admin_session.s_state.input_packets++;
- admin_session.s_state.input_octets += len;
- }
- }
- }
- }
- #ifdef ENABLE_LEAKYBUCKET
- #ifdef COUNT_DOWNLINK_DROP
- if (do_bw) {
- if (leaky_bucket(appconn, 0, len)) return 1;
- }
- #endif
- #endif
- }
- appconn->s_state.last_time = mainclock.tv_sec;
- return 0;
- }
- #ifdef ENABLE_EAPOL
- /* Callback for receiving messages from eapol */
- int cb_dhcp_eap_ind(struct dhcp_conn_t *conn, uint8_t *pack, size_t len) {
- struct eap_packet_t *eap = (struct eap_packet_t *)pack;
- struct app_conn_t *appconn = conn->peer;
- struct radius_packet_t radius_pack;
- size_t offset;
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): EAP Packet received", __FUNCTION__, __LINE__);
- #endif
- /* If this is the first EAPOL authentication request */
- if ((appconn->dnprot == DNPROT_DHCP_NONE) ||
- (appconn->dnprot == DNPROT_EAPOL)) {
- if ((eap->code == 2) && /* Response */
- (eap->type == 1) && /* Identity */
- (len > 5) && /* Must be at least 5 octets */
- ((len - 5) < REDIR_USERNAMESIZE-1 )) {
- memcpy(appconn->s_state.redir.username, eap->payload, len - 5);
- appconn->s_state.redir.username[len - 5] = 0;
- appconn->dnprot = DNPROT_EAPOL;
- appconn->authtype = EAP_MESSAGE;
- }
- else if (appconn->dnprot == DNPROT_DHCP_NONE) {
- syslog(LOG_ERR, "Initial EAP response was not a valid identity response!");
- return 0;
- }
- }
- /* Return if not EAPOL */
- if (appconn->dnprot != DNPROT_EAPOL) {
- syslog(LOG_WARNING, "Received EAP message, processing for authentication");
- appconn->dnprot = DNPROT_EAPOL;
- return 0;
- }
- if (radius_default_pack(radius, &radius_pack, RADIUS_CODE_ACCESS_REQUEST)) {
- syslog(LOG_ERR, "radius_default_pack() failed");
- return -1;
- }
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_NAME, 0, 0, 0,
- (uint8_t*) appconn->s_state.redir.username,
- strlen(appconn->s_state.redir.username));
- /* Include EAP (if present) */
- offset = 0;
- while (offset < len) {
- size_t eaplen;
- if ((len - offset) > RADIUS_ATTR_VLEN)
- eaplen = RADIUS_ATTR_VLEN;
- else
- eaplen = len - offset;
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_EAP_MESSAGE, 0, 0, 0,
- pack + offset, eaplen);
- offset += eaplen;
- }
- chilli_req_attrs(radius, &radius_pack,
- ACCT_USER,
- _options.framedservice ? RADIUS_SERVICE_TYPE_FRAMED :
- RADIUS_SERVICE_TYPE_LOGIN, 0,
- appconn->unit, appconn->hismac,
- &appconn->hisip, &appconn->s_state);
- radius_addattr(radius, &radius_pack, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
- 0, 0, 0, NULL, RADIUS_MD5LEN);
- return radius_req(radius, &radius_pack, appconn);
- }
- #endif
- /***********************************************************
- *
- * uam message handling functions
- *
- ***********************************************************/
- int static uam_msg(struct redir_msg_t *msg) {
- struct ippoolm_t *ipm;
- struct app_conn_t *appconn = NULL;
- struct dhcp_conn_t* dhcpconn;
- #if defined(HAVE_NETFILTER_QUEUE) || defined(HAVE_NETFILTER_COOVA)
- if (_options.uamlisten.s_addr != _options.dhcplisten.s_addr) {
- msg->mdata.address.sin_addr.s_addr = msg->mdata.address.sin_addr.s_addr & ~(_options.mask.s_addr);
- msg->mdata.address.sin_addr.s_addr |= _options.dhcplisten.s_addr & _options.mask.s_addr;
- }
- #endif
- if (ippool_getip(ippool, &ipm, &msg->mdata.address.sin_addr)) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): UAM login with unknown IP address: %s", __FUNCTION__, __LINE__, inet_ntoa(msg->mdata.address.sin_addr));
- return 0;
- }
- if ((appconn = (struct app_conn_t *)ipm->peer) == NULL ||
- (dhcpconn = (struct dhcp_conn_t *)appconn->dnlink) == NULL) {
- syslog(LOG_ERR, "No peer protocol defined");
- return 0;
- }
- if (appconn->s_state.authenticated == 0 || msg->mtype == REDIR_LOGOUT) {
- /* Ensure that the session is not already authenticated before changing session */
- if (msg->mdata.opt & REDIR_MSG_OPT_REDIR)
- memcpy(&appconn->s_state.redir, &msg->mdata.redir, sizeof(msg->mdata.redir));
- if (msg->mdata.opt & REDIR_MSG_OPT_PARAMS)
- memcpy(&appconn->s_params, &msg->mdata.params, sizeof(msg->mdata.params));
- if (msg->mdata.opt & REDIR_MSG_NSESSIONID)
- set_sessionid(appconn, 0);
- }
- switch(msg->mtype) {
- case REDIR_LOGIN:
- if (appconn->uamabort) {
- syslog(LOG_INFO, "UAM login from username=%s IP=%s was aborted!",
- msg->mdata.redir.username, inet_ntoa(appconn->hisip));
- appconn->uamabort = 0;
- return 0;
- }
- syslog(LOG_INFO, "Successful UAM login from username=%s IP=%s",
- msg->mdata.redir.username, inet_ntoa(appconn->hisip));
- /* Initialise */
- appconn->s_params.routeidx = tun->routeidx;
- appconn->s_state.redir.statelen = 0;
- #ifdef ENABLE_RADPROXY
- appconn->challen = 0;
- appconn->sendlen = 0;
- appconn->recvlen = 0;
- appconn->lmntlen = 0;
- #endif
- memcpy(appconn->hismac, dhcpconn->hismac, PKT_ETH_ALEN);
- #ifdef ENABLE_LEAKYBUCKET
- leaky_bucket_init(appconn);
- #endif
- return upprot_getip(appconn, 0, 0);
- case REDIR_LOGOUT:
- syslog(LOG_INFO, "Received UAM logoff from username=%s IP=%s",
- appconn->s_state.redir.username, inet_ntoa(appconn->hisip));
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Received logoff from UAM", __FUNCTION__, __LINE__);
- if (appconn->s_state.authenticated == 1) {
- #ifdef ENABLE_SESSIONSTATE
- appconn->s_state.session_state =
- RADIUS_VALUE_COOVACHILLI_SESSION_USER_LOGOUT_URL;
- #endif
- terminate_appconn(appconn, RADIUS_TERMINATE_CAUSE_USER_REQUEST);
- appconn->s_params.sessiontimeout = 0;
- appconn->s_params.idletimeout = 0;
- }
- appconn->uamabort = 0;
- appconn->s_state.uamtime = mainclock.tv_sec;
- #ifdef ENABLE_LAYER3
- if (!_options.layer3)
- #endif
- dhcpconn->authstate = DHCP_AUTH_DNAT;
- break;
- case REDIR_ABORT:
- syslog(LOG_INFO, "Received UAM abort from IP=%s", inet_ntoa(appconn->hisip));
- appconn->uamabort = 1; /* Next login will be aborted */
- appconn->s_state.uamtime = 0; /* Force generation of new challenge */
- #ifdef ENABLE_LAYER3
- if (!_options.layer3)
- #endif
- dhcpconn->authstate = DHCP_AUTH_DNAT;
- terminate_appconn(appconn, RADIUS_TERMINATE_CAUSE_USER_REQUEST);
- break;
- case REDIR_CHALLENGE:
- appconn->s_state.uamtime = mainclock.tv_sec;
- appconn->uamabort = 0;
- break;
- case REDIR_MACREAUTH:
- auth_radius(appconn, 0, 0, 0, 0);
- break;
- case REDIR_ALREADY:
- case REDIR_NOTYET:
- break;
- }
- return 0;
- }
- #if defined(ENABLE_CHILLIQUERY) || defined(ENABLE_CLUSTER)
- static struct app_conn_t * find_app_conn(struct cmdsock_request *req,
- int *has_criteria) {
- struct app_conn_t *appconn = 0;
- struct dhcp_conn_t *dhcpconn = 0;
- if (req->ip.s_addr) {
- appconn = dhcp_get_appconn_ip(0, &req->ip);
- if (has_criteria)
- *has_criteria = 1;
- } else {
- #ifdef ENABLE_LAYER3
- if (!_options.layer3)
- #endif
- if (req->mac[0]||req->mac[1]||req->mac[2]||
- req->mac[3]||req->mac[4]||req->mac[5]) {
- dhcp_hashget(dhcp, &dhcpconn, req->mac);
- if (has_criteria)
- *has_criteria = 1;
- }
- }
- if (!appconn && dhcpconn
- #ifdef ENABLE_LAYER3
- && !_options.layer3
- #endif
- )
- appconn = (struct app_conn_t *) dhcpconn->peer;
- if (!appconn && req->d.sess.sessionid[0] != 0) {
- struct app_conn_t *aconn = firstusedconn;
- if (has_criteria)
- *has_criteria = 1;
- while (aconn) {
- if (!strcmp(aconn->s_state.sessionid, req->d.sess.sessionid)) {
- appconn = aconn;
- break;
- }
- aconn = aconn->next;
- }
- }
- if (appconn && !appconn->inuse) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): appconn not in use!", __FUNCTION__, __LINE__);
- return 0;
- }
- return appconn;
- }
- int chilli_cmd(struct cmdsock_request *req, bstring s, int sock) {
- #ifdef HAVE_NETFILTER_COOVA
- if (_options.kname) {
- kmod_coova_sync();
- }
- #endif
- switch(req->type) {
- #ifdef ENABLE_INSPECT
- case CMDSOCK_INSPECT:
- {
- struct app_conn_t *appconn = 0;
- struct dhcp_conn_t *dhcpconn = 0;
- uint8_t z[PKT_ETH_ALEN];
- memset(z, 0, PKT_ETH_ALEN);
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): looking to inspect ip=%s/mac="MAC_FMT, __FUNCTION__, __LINE__,
- inet_ntoa(req->ip), MAC_ARG(req->mac));
- if (req->ip.s_addr)
- appconn = dhcp_get_appconn_ip(0, &req->ip);
- else
- #ifdef ENABLE_LAYER3
- if (!_options.layer3)
- #endif
- dhcp_hashget(dhcp, &dhcpconn, req->mac);
- if (!appconn && !dhcpconn) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): not found", __FUNCTION__, __LINE__);
- } else {
- bstring tmp = bfromcstr("");
- uint32_t sessiontime = 0;
- uint32_t idletime = 0;
- char *down="down";
- char *up="up";
- char *in_label=down;
- char *out_label=up;
- if (!appconn)
- appconn = (struct app_conn_t *) dhcpconn->peer;
- if (!dhcpconn
- #ifdef ENABLE_LAYER3
- && !_options.layer3
- #endif
- )
- dhcpconn = (struct dhcp_conn_t *) appconn->dnlink;
- if (_options.swapoctets) {
- in_label=up;
- out_label=down;
- }
- if (appconn->s_state.authenticated) {
- sessiontime = mainclock_diffu(appconn->s_state.start_time);
- idletime = mainclock_diffu(appconn->s_state.last_up_time);
- }
- bassignformat(tmp,
- "MAC: "MAC_FMT" IP: %s\n"
- "---------------------------------------------------\n",
- MAC_ARG(appconn->hismac),
- inet_ntoa(appconn->hisip));
- bconcat(s, tmp);
- #ifdef ENABLE_IEEE8021Q
- /* adding: vlan, if one */
- if (_options.ieee8021q && appconn->s_state.tag8021q) {
- bassignformat(tmp, "%20s: %d\n",
- "vlan",
- (int)ntohs(appconn->s_state.tag8021q &
- PKT_8021Q_MASK_VID));
- bconcat(s, tmp);
- } else {
- #endif
- #ifdef ENABLE_MULTILAN
- if (app_conn_idx(appconn)) {
- bassignformat(tmp,
- "%20s: %s\n"
- "%20s: %s\n",
- "dhcpif",
- _options.moreif[app_conn_idx(appconn)-1].dhcpif,
- "vlan",
- _options.moreif[app_conn_idx(appconn)-1].vlan ?
- _options.moreif[app_conn_idx(appconn)-1].vlan :
- _options.moreif[app_conn_idx(appconn)-1].dhcpif);
- } else {
- bassignformat(tmp,
- "%20s: %s\n"
- "%20s: %s\n",
- "dhcpif",
- _options.dhcpif,
- "vlan",
- _options.vlan);
- }
- bconcat(s, tmp);
- #endif
- #ifdef ENABLE_IEEE8021Q
- }
- #endif
- bassignformat(tmp,
- "%20s:%s authenticated\n",
- "status",
- appconn->s_state.authenticated ?
- "" : " not");
- bconcat(s, tmp);
- {
- char buffer[128];
- redir_chartohex(appconn->s_state.redir.uamchal,
- buffer, REDIR_MD5LEN);
- bassignformat(tmp,
- "%20s: %s\n",
- "challenge",
- buffer);
- bconcat(s, tmp);
- }
- bassignformat(tmp,
- "%20s: %.*s\n",
- "session id",
- appconn->s_state.sessionid[0] ?
- strlen(appconn->s_state.sessionid) : 1,
- appconn->s_state.sessionid[0] ?
- appconn->s_state.sessionid : "-");
- bconcat(s, tmp);
- #ifdef ENABLE_SESSIONID
- bassignformat(tmp,
- "%20s: %s\n",
- "chilli session id",
- appconn->s_state.chilli_sessionid);
- bconcat(s, tmp);
- #endif
- #ifdef ENABLE_GARDENACCOUNTING
- if (appconn->s_state.garden_sessionid[0]) {
- bassignformat(tmp,
- "%20s: %s\n",
- "garden session id",
- appconn->s_state.garden_sessionid);
- bconcat(s, tmp);
- }
- #endif
- #ifdef ENABLE_APSESSIONID
- if (appconn->s_state.ap_sessionid[0]) {
- bassignformat(tmp,
- "%20s: %s\n",
- "ap session id",
- appconn->s_state.ap_sessionid);
- bconcat(s, tmp);
- }
- #endif
- #ifdef ENABLE_LOCATION
- if (appconn->s_state.location[0]) {
- bassignformat(tmp,
- "%20s: %s\n",
- "location",
- appconn->s_state.location);
- bconcat(s, tmp);
- }
- if (appconn->s_state.pending_location[0]) {
- bassignformat(tmp,
- "%20s: %s\n",
- "pending location",
- appconn->s_state.pending_location);
- bconcat(s, tmp);
- }
- if (appconn->s_state.location_changes) {
- bassignformat(tmp,
- "%20s: %d\n",
- "location changes",
- appconn->s_state.location_changes);
- bconcat(s, tmp);
- }
- #endif
- bassignformat(tmp,
- "%20s: %.*s\n",
- "user name",
- appconn->s_state.redir.username[0] ?
- strlen(appconn->s_state.redir.username) : 1,
- appconn->s_state.redir.username[0] ?
- appconn->s_state.redir.username : "-");
- bconcat(s, tmp);
- bassignformat(tmp,
- "%20s: %d sec\n"
- "%20s: %d sec\n"
- "%20s: %d sec\n"
- "%20s: %d sec\n",
- "session time",
- sessiontime,
- "session timeout",
- (int)appconn->s_params.sessiontimeout,
- "idle time",
- idletime,
- "idle timeout",
- (int)appconn->s_params.idletimeout);
- bconcat(s, tmp);
- bassignformat(tmp,
- "%20s: in=%s, out=%s\n",
- "octets in/out",
- in_label, out_label);
- bconcat(s, tmp);
- if (appconn->s_params.maxtotaloctets) {
- bassignformat(tmp,
- "%20s: %lld\n",
- "max total octets",
- appconn->s_params.maxtotaloctets);
- bconcat(s, tmp);
- }
- bassignformat(tmp,
- "%20s: %lld\n",
- "octets in",
- appconn->s_state.input_octets);
- bconcat(s, tmp);
- if (appconn->s_params.maxinputoctets) {
- bassignformat(tmp,
- "%20s: %lld\n",
- "max octets in",
- appconn->s_params.maxinputoctets);
- bconcat(s, tmp);
- }
- #ifdef ENABLE_GARDENACCOUNTING
- if (_options.uamgardendata) {
- bassignformat(tmp,
- "%20s: %lld\n",
- "garden octets in",
- appconn->s_state.garden_input_octets);
- bconcat(s, tmp);
- if (_options.uamotherdata) {
- bassignformat(tmp,
- "%20s: %lld\n",
- "other octets in",
- appconn->s_state.other_input_octets);
- bconcat(s, tmp);
- }
- }
- #endif
- bassignformat(tmp,
- "%20s: %lld\n",
- "octets out",
- appconn->s_state.output_octets);
- bconcat(s, tmp);
- if (appconn->s_params.maxoutputoctets) {
- bassignformat(tmp,
- "%20s: %lld\n",
- "max octets out",
- appconn->s_params.maxoutputoctets);
- bconcat(s, tmp);
- }
- #ifdef ENABLE_GARDENACCOUNTING
- if (_options.uamgardendata) {
- bassignformat(tmp,
- "%20s: %lld\n",
- "garden octets out",
- appconn->s_state.garden_output_octets);
- bconcat(s, tmp);
- if (_options.uamotherdata) {
- bassignformat(tmp,
- "%20s: %lld\n",
- "other octets out",
- appconn->s_state.other_output_octets);
- bconcat(s, tmp);
- }
- }
- #endif
- bassignformat(tmp,
- "%20s: %lld (%d%%)\n"
- "%20s: %lld (%d%%)\n",
- "max b/w up",
- appconn->s_params.bandwidthmaxup,
- appconn->s_state.bucketupsize ?
- (int) (appconn->s_state.bucketup * 100
- / appconn->s_state.bucketupsize) : 0,
- "max b/w down",
- appconn->s_params.bandwidthmaxdown,
- appconn->s_state.bucketdownsize ?
- (int) (appconn->s_state.bucketdown * 100
- / appconn->s_state.bucketdownsize) : 0);
- bconcat(s, tmp);
- bassignformat(tmp,
- "%20s: %d sec ago\n",
- "last sent time",
- appconn->s_state.last_up_time ?
- mainclock_now()-appconn->s_state.last_up_time:0);
- bconcat(s, tmp);
- if (dhcpconn) {
- bassignformat(tmp,
- "%20s: %d sec ago\n",
- "last seen",
- dhcpconn->lasttime ?
- mainclock_now()-dhcpconn->lasttime:0);
- bconcat(s, tmp);
- }
- bassignformat(tmp,
- "%20s: %s\n",
- "user url",
- appconn->s_state.redir.userurl);
- bconcat(s, tmp);
- #ifdef ENABLE_USERAGENT
- if (appconn->s_state.redir.useragent[0]) {
- bassignformat(tmp,
- "%20s: %s\n",
- "user agent",
- appconn->s_state.redir.useragent);
- bconcat(s, tmp);
- }
- #endif
- #ifdef ENABLE_ACCEPTLANGUAGE
- if (appconn->s_state.redir.acceptlanguage[0]) {
- bassignformat(tmp,
- "%20s: %s\n",
- "accept language",
- appconn->s_state.redir.acceptlanguage);
- bconcat(s, tmp);
- }
- #endif
- bassignformat(tmp,
- "%20s: %s\n",
- "url param",
- appconn->s_params.url);
- bconcat(s, tmp);
- bassignformat(tmp,
- "%20s:",
- "flags");
- if (appconn->s_params.flags & REQUIRE_UAM_AUTH)
- bcatcstr(tmp, " require-uam-auth");
- if (appconn->s_params.flags & REQUIRE_UAM_SPLASH)
- bcatcstr(tmp, " uam-splash");
- if (appconn->s_params.flags & REQUIRE_REDIRECT)
- bcatcstr(tmp, " require-redirect");
- if (appconn->s_params.flags & NO_ACCOUNTING)
- bcatcstr(tmp, " no-accounting");
- if (appconn->s_params.flags & NO_SCRIPT)
- bcatcstr(tmp, " no-script");
- if (appconn->s_params.flags & UAM_INJECT_URL)
- bcatcstr(tmp, " inject");
- if (appconn->s_params.flags & UAM_CLEAR_URL)
- bcatcstr(tmp, " clear-url");
- bcatcstr(tmp, "\n");
- bconcat(s, tmp);
- #ifdef ENABLE_PROXYVSA
- bassignformat(tmp, "%20s: %d\n",
- "vsa length",
- (int)appconn->s_state.redir.vsalen);
- bconcat(s, tmp);
- #endif
- #ifdef ENABLE_SESSGARDEN
- if (appconn->s_params.pass_through_count > 0) {
- char mask[32];
- pass_through *pt;
- int i;
- bassignformat(tmp,
- "%20s: %d\n",
- "garden entries",
- appconn->s_params.pass_through_count);
- bconcat(s, tmp);
- for (i = 0; i < appconn->s_params.pass_through_count; i++) {
- pt = &appconn->s_params.pass_throughs[i];
- strlcpy(mask, inet_ntoa(pt->mask), sizeof(mask));
- bassignformat(tmp,
- "%20s: host=%-16s mask=%-16s proto=%-3d port=%-3d"
- #ifdef ENABLE_GARDENEXT
- " expiry=%-3d"
- #endif
- "\n", "",
- inet_ntoa(pt->host), mask,
- pt->proto, pt->port
- #ifdef ENABLE_GARDENEXT
- , pt->expiry ? pt->expiry - mainclock_now() : 0
- #endif
- );
- bconcat(s, tmp);
- }
- }
- #endif
- bdestroy(tmp);
- }
- }
- break;
- #endif
- case CMDSOCK_ADD_GARDEN:
- case CMDSOCK_REM_GARDEN:
- {
- char remove = (req->type == CMDSOCK_REM_GARDEN);
- #ifdef ENABLE_SESSGARDEN
- uint8_t z[PKT_ETH_ALEN];
- memset(z, 0, PKT_ETH_ALEN);
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): looking to %s to garden ip=%s/sessionid=%s", __FUNCTION__, __LINE__,
- remove ? "remove" : "add", inet_ntoa(req->ip), req->d.sess.sessionid);
- if (req->ip.s_addr || memcmp(req->mac, z, PKT_ETH_ALEN)) {
- struct app_conn_t *appconn = firstusedconn;
- while (appconn) {
- if (appconn->inuse &&
- ( (req->ip.s_addr != 0 && appconn->hisip.s_addr == req->ip.s_addr) ||
- (!memcmp(appconn->hismac, req->mac, PKT_ETH_ALEN))
- ) ) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): remote %s garden for session %s", __FUNCTION__, __LINE__,
- remove ? "rem" : "add", appconn->s_state.sessionid);
- #ifdef HAVE_PATRICIA
- if (appconn->ptree == NULL)
- appconn->ptree = patricia_new (32);
- #endif
- pass_throughs_from_string(appconn->s_params.pass_throughs,
- SESSION_PASS_THROUGH_MAX,
- &appconn->s_params.pass_through_count,
- req->d.data, 1, remove
- #ifdef HAVE_PATRICIA
- , appconn->ptree
- #endif
- );
- break;
- }
- appconn = appconn->next;
- }
- } else {
- #endif
- pass_throughs_from_string(dhcp->pass_throughs,
- MAX_PASS_THROUGHS,
- &dhcp->num_pass_throughs,
- req->d.data, 1, remove
- #ifdef HAVE_PATRICIA
- , dhcp->ptree_dyn
- #endif
- );
- #ifdef ENABLE_SESSGARDEN
- }
- #endif
- }
- break;
- case CMDSOCK_LOGOUT:
- {
- struct app_conn_t *appconn = find_app_conn(req, 0);
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): looking to logout session %s", __FUNCTION__, __LINE__,
- inet_ntoa(req->ip));
- if (appconn) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): found %s %s", __FUNCTION__, __LINE__,
- inet_ntoa(appconn->hisip), appconn->s_state.sessionid);
- terminate_appconn(appconn, RADIUS_TERMINATE_CAUSE_ADMIN_RESET);
- }
- }
- break;
- case CMDSOCK_LIST_IPPOOL:
- ippool_print(sock, ippool);
- break;
- case CMDSOCK_LIST_GARDEN:
- garden_print(sock);
- break;
- case CMDSOCK_LIST_RADQUEUE:
- radius_printqueue(sock, radius);
- break;
- case CMDSOCK_LIST:
- {
- int listfmt = (req->options & CMDSOCK_OPT_JSON) ?
- LIST_JSON_FMT : LIST_LONG_FMT;
- struct app_conn_t *appconn=0;
- struct dhcp_conn_t *dhcpconn=0;
- int crt = 0;
- #ifdef ENABLE_JSON
- if (listfmt == LIST_JSON_FMT) {
- bcatcstr(s, "{ \"sessions\":[");
- }
- #endif
- appconn = find_app_conn(req, &crt);
- if (appconn) {
- #ifdef ENABLE_LAYER3
- if (!_options.layer3)
- #endif
- dhcpconn = (struct dhcp_conn_t *)appconn->dnlink;
- chilli_print(s, listfmt, appconn, dhcpconn);
- } else if (!crt) {
- #ifdef ENABLE_LAYER3
- if (_options.layer3) {
- for (appconn = firstusedconn; appconn;
- appconn = appconn->next) {
- chilli_print(s, listfmt, appconn, 0);
- }
- } else {
- #endif
- if (dhcp) {
- dhcpconn = dhcp->firstusedconn;
- while (dhcpconn) {
- chilli_print(s, listfmt, 0, dhcpconn);
- dhcpconn = dhcpconn->next;
- }
- }
- #ifdef ENABLE_LAYER3
- }
- #endif
- }
- #ifdef ENABLE_JSON
- if (listfmt == LIST_JSON_FMT) {
- bcatcstr(s, "]}");
- }
- #endif
- }
- break;
- case CMDSOCK_DHCP_LIST:
- if (dhcp) {
- int listfmt = req->options & CMDSOCK_OPT_JSON ?
- LIST_JSON_FMT : LIST_SHORT_FMT;
- struct dhcp_conn_t *conn;
- #ifdef ENABLE_JSON
- if (listfmt == LIST_JSON_FMT) {
- bcatcstr(s, "{ \"sessions\":[");
- }
- #endif
- conn = dhcp->firstusedconn;
- while (conn) {
- chilli_print(s, listfmt, 0, conn);
- conn = conn->next;
- }
- #ifdef ENABLE_JSON
- if (listfmt == LIST_JSON_FMT) {
- bcatcstr(s, "]}");
- }
- #endif
- }
- break;
- case CMDSOCK_DHCP_DROP:
- if (dhcp)
- dhcp_block_mac(dhcp, req->mac);
- break;
- case CMDSOCK_DHCP_RELEASE:
- if (dhcp)
- dhcp_release_mac(dhcp, req->mac,
- RADIUS_TERMINATE_CAUSE_ADMIN_RESET);
- break;
- #ifdef ENABLE_MULTIROUTE
- case CMDSOCK_ROUTE_SET:
- case CMDSOCK_ROUTE_GW:
- {
- if (req->type == CMDSOCK_ROUTE_GW) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): setting route for idx %d", __FUNCTION__, __LINE__, req->d.sess.params.routeidx);
- copy_mac6(tun(tun, req->d.sess.params.routeidx).gwaddr, req->mac);
- } else {
- struct dhcp_conn_t *conn = dhcp->firstusedconn;
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): looking to alter session %s", __FUNCTION__, __LINE__, inet_ntoa(req->ip));
- while (conn && conn->inuse) {
- if (conn->peer) {
- struct app_conn_t * appconn = (struct app_conn_t*)conn->peer;
- if (!memcmp(appconn->hismac, req->mac, 6)) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): routeidx %s %d", __FUNCTION__, __LINE__,
- appconn->s_state.sessionid,
- req->d.sess.params.routeidx);
- appconn->s_params.routeidx = req->d.sess.params.routeidx;
- break;
- }
- }
- conn = conn->next;
- }
- }
- }
- /* drop through */
- case CMDSOCK_ROUTE:
- {
- int i;
- bstring b = bfromcstr("routes:\n");
- int err = 0;
- if (safe_write(sock, b->data, b->slen) == b->slen) {
- for (i=0; !err && i<tun->_interface_count; i++) {
- char gw[56];
- strlcpy(gw, inet_ntoa(tun->_interfaces[i].gateway), sizeof(gw));
- bassignformat(b, "idx: %d dev: %s %s "MAC_FMT" "
- "%s "MAC_FMT"%s\n",
- i, tun->_interfaces[i].devname,
- inet_ntoa(tun->_interfaces[i].address),
- MAC_ARG(tun->_interfaces[i].hwaddr),
- gw,
- MAC_ARG(tun->_interfaces[i].gwaddr),
- i == 0 ? " (tun/tap)":"");
- if (safe_write(sock, b->data, b->slen) < 0)
- err = 1;
- }
- if (!err) {
- struct dhcp_conn_t *conn = dhcp->firstusedconn;
- bassignformat(b, "subscribers:\n");
- if (safe_write(sock, b->data, b->slen) == b->slen) {
- while (conn) {
- struct app_conn_t *appconn = (struct app_conn_t *)conn->peer;
- bassignformat(b, "mac: "MAC_FMT" -> idx: %d\n",
- MAC_ARG(appconn->hismac),
- appconn->s_params.routeidx);
- if (safe_write(sock, b->data, b->slen) < 0)
- break;
- conn = conn->next;
- }
- }
- }
- }
- bdestroy(b);
- }
- rtmon_print_ifaces(&_rtmon, sock);
- rtmon_print_routes(&_rtmon, sock);
- break;
- #endif
- case CMDSOCK_LOGIN:
- case CMDSOCK_UPDATE:
- case CMDSOCK_AUTHORIZE:
- if (dhcp) {
- struct app_conn_t *appconn = find_app_conn(req, 0);
- if (appconn) {
- char *uname = req->d.sess.username;
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): remotely authorized session %s", __FUNCTION__, __LINE__,
- appconn->s_state.sessionid);
- memcpy(&appconn->s_params, &req->d.sess.params,
- sizeof(req->d.sess.params));
- if (uname[0])
- strlcpy(appconn->s_state.redir.username,
- uname, USERNAMESIZE);
- session_param_defaults(&appconn->s_params);
- #ifdef ENABLE_LEAKYBUCKET
- leaky_bucket_init(appconn);
- #endif
- switch(req->type) {
- case CMDSOCK_LOGIN:
- auth_radius(appconn, uname, req->d.sess.password, 0, 0);
- break;
- case CMDSOCK_AUTHORIZE:
- dnprot_accept(appconn);
- break;
- case CMDSOCK_UPDATE:
- break;
- }
- }
- }
- break;
- #if defined(ENABLE_LOCATION) && defined(HAVE_AVL)
- case CMDSOCK_LISTLOC:
- case CMDSOCK_LISTLOCSUM:
- location_printlist(s, req->d.sess.location,
- (req->options & CMDSOCK_OPT_JSON),
- (req->type == CMDSOCK_LISTLOC));
- break;
- #endif
- case CMDSOCK_RELOAD:
- _sigusr1(SIGUSR1);
- break;
- #ifdef ENABLE_STATFILE
- case CMDSOCK_STATUSFILE:
- printstatus();
- break;
- #endif
- #ifdef ENABLE_CLUSTER
- case CMDSOCK_PEERS:
- print_peers(s);
- break;
- case CMDSOCK_PEER_SET:
- get_chilli_peer(-1)->state = PEER_STATE_ACTIVE;
- dhcp_peer_update(1);
- break;
- #endif
- case CMDSOCK_PROCS:
- child_print(s);
- break;
- default:
- {
- char unknown = 1;
- #ifdef ENABLE_MODULES
- int i;
- for (i=0; i < MAX_MODULES; i++) {
- if (!_options.modules[i].name[0]) break;
- if (_options.modules[i].ctx) {
- struct chilli_module *m =
- (struct chilli_module *)_options.modules[i].ctx;
- if (m->cmdsock_handler) {
- switch (m->cmdsock_handler(req, s, sock)) {
- case CHILLI_CMDSOCK_OK:
- unknown = 0;
- break;
- }
- }
- }
- }
- #endif
- if (unknown) {
- syslog(LOG_ERR, "unknown cmdsock command");
- safe_close(sock);
- return -1;
- }
- }
- }
- return 0;
- }
- #endif
- #ifdef ENABLE_CHILLIQUERY
- static int cmdsock_accept(void *nullData, int sock) {
- struct sockaddr_un remote;
- struct cmdsock_request req;
- bstring s = 0;
- socklen_t len;
- int csock;
- int rval = 0;
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Processing cmdsock request...", __FUNCTION__, __LINE__);
- #endif
- len = sizeof(remote);
- if ((csock = safe_accept(sock, (struct sockaddr *)&remote, &len)) == -1) {
- syslog(LOG_ERR, "%s: cmdsock_accept()/accept()", strerror(errno));
- return -1;
- }
- if (safe_read(csock, &req, sizeof(req)) != sizeof(req)) {
- syslog(LOG_ERR, "%s: cmdsock_accept()/read()", strerror(errno));
- safe_close(csock);
- return -1;
- }
- s = bfromcstr("");
- if (s == NULL) {
- syslog(LOG_ERR, "bfromstr(): memory allocation error");
- safe_close(csock);
- return -1;
- }
- rval = chilli_cmd(&req, s, csock);
- if (net_write(csock, s->data, s->slen) < 0)
- syslog(LOG_ERR, "%s: write()", strerror(errno));
- bdestroy(s);
- shutdown(csock, 2);
- safe_close(csock);
- return rval;
- }
- #endif
- #if XXX_IO_DAEMON
- int chilli_io(int fd_ctrl_r, int fd_ctrl_w, int fd_pkt_r, int fd_pkt_w) {
- int maxfd = 0;
- fd_set fds;
- int status;
- while (1) {
- fd_zero(&fds);
- fd_set(fd_ctrl_r, &fds);
- fd_set(fd_ctrl_w, &fds);
- fd_set(fd_pkt_r, &fds);
- fd_set(fd_pkt_w, &fds);
- if ((status = select(maxfd + 1, &fds, NULL, NULL, NULL)) == -1) {
- if (EINTR != errno) {
- syslog(LOG_ERR, "select() returned -1!");
- }
- }
- if (status > 0) {
- if (fd_isset(fd_ctrl_r, &fds)) {
- }
- if (fd_isset(fd_ctrl_w, &fds)) {
- }
- if (fd_isset(fd_pkt_r, &fds)) {
- }
- if (fd_isset(fd_pkt_w, &fds)) {
- }
- } else {
- syslog(LOG_ERR, "%s: problem in select", strerror(errno));
- break;
- }
- }
- exit(1);
- }
- #endif
- #ifdef USING_IPC_UNIX
- int static redir_msg(struct redir_t *this) {
- struct redir_msg_t msg;
- struct sockaddr_un remote;
- socklen_t len = sizeof(remote);
- int socket = safe_accept(this->msgfd, (struct sockaddr *)&remote, &len);
- if (socket > 0) {
- int msgresult = safe_read(socket, &msg, sizeof(msg));
- if (msgresult == sizeof(msg)) {
- if (msg.mtype == REDIR_MSG_STATUS_TYPE) {
- struct redir_conn_t conn;
- memset(&conn, 0, sizeof(conn));
- if (cb_redir_getstate(redir,
- &msg.mdata.address,
- &msg.mdata.baddress,
- &conn) != -1) {
- if (safe_write(socket, &conn, sizeof(conn)) < 0) {
- syslog(LOG_ERR, "%s: redir_msg writing", strerror(errno));
- }
- }
- } else {
- uam_msg(&msg);
- }
- } else if (msgresult == -1) {
- syslog(LOG_ERR, "%s: redir_msg read", strerror(errno));
- } else {
- syslog(LOG_ERR, "invalid size %d", msgresult);
- }
- safe_close(socket);
- }
- return 0;
- }
- #endif
- #ifdef ENABLE_MULTIROUTE
- int chilli_getconn_byroute(struct app_conn_t **conn, int idx) {
- struct app_conn_t *appconn = firstusedconn;
- while (appconn) {
- if (appconn->s_params.routeidx == idx) {
- *conn = appconn;
- return 0;
- }
- appconn = appconn->next;
- }
- return 1;
- }
- static int rtmon_proc_route(struct rtmon_t *rtmon,
- struct rtmon_iface *iface,
- struct rtmon_route *route) {
- int i;
- for (i=0; i < tun->_interface_count; i++) {
- if (tun->_interfaces[i].ifindex == route->if_index) {
- memcpy(tun->_interfaces[i].gwaddr, route->gwaddr, sizeof(tun->_interfaces[i].gwaddr));
- tun->_interfaces[i].gateway.s_addr = route->gateway.s_addr;
- }
- }
- return 0;
- }
- static int rtmon_accept(struct rtmon_t *rtmon, int idx) {
- if (rtmon_read_event(rtmon))
- syslog(LOG_ERR, "%s: error reading netlink message", strerror(errno));
- return 0;
- }
- #endif
- static inline void macauth_reserved() {
- struct dhcp_conn_t *conn = dhcp->firstusedconn;
- struct app_conn_t *appconn;
- while (conn) {
- if (conn->is_reserved && conn->peer) {
- appconn = (struct app_conn_t *)conn->peer;
- if (!appconn->s_state.authenticated) {
- auth_radius((struct app_conn_t *)conn->peer, 0, 0, 0, 0);
- }
- }
- conn = conn->next;
- }
- }
- #ifdef ENABLE_LAYER3
- static int session_timeout() {
- struct app_conn_t *conn = firstusedconn;
- while (conn) {
- struct app_conn_t *check_conn = conn;
- conn = conn->next;
- if (mainclock_diff(check_conn->s_state.last_up_time) >
- _options.lease + _options.leaseplus) {
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Session timeout: Removing connection", __FUNCTION__, __LINE__);
- session_disconnect(check_conn, 0, RADIUS_TERMINATE_CAUSE_LOST_CARRIER);
- }
- }
- return 0;
- }
- #endif
- int chilli_main(int argc, char **argv) {
- select_ctx sctx;
- int status;
- /* struct itimerval itval; */
- int lastSecond = 0;
- #ifdef ENABLE_CHILLIQUERY
- int cmdsock = -1;
- #endif
- pid_t cpid = getpid();
- #ifdef USING_IPC_MSG
- struct redir_msg_t msg;
- int msgresult;
- #endif
- #if XXX_IO_DAEMON
- pid_t chilli_fork = 0;
- int is_slave = 0;
- int ctrl_main_to_io[2]; /* 0/1 read/write - control messages from main -> io */
- int ctrl_io_to_main[2]; /* 0/1 read/write - control messages from io -> main */
- int pkt_main_to_io[2];
- int pkt_io_to_main[2];
- #endif
- int i;
- int keep_going = 1;
- int reload_config = 0;
- int syslog_options = LOG_PID;
- int syslog_debug_options = 0;
- char *syslog_ident = NULL;
- #ifdef LOG_PERROR
- syslog_debug_options = LOG_PERROR;
- #endif
- syslog_ident = basename(argv[0]);
- /* Start out also logging to stderr until we load options. */
- openlog(syslog_ident, syslog_options|syslog_debug_options, LOG_DAEMON);
- options_init();
- /* Process options given in configuration file and command line */
- if (process_options(argc, argv, 0))
- exit(1);
- /* foreground */
- /* If flag not given run as a daemon */
- if (!_options.foreground) {
- FILE *fp = NULL;
- if (!(fp = freopen("/dev/null", "w", stdout))) {
- syslog(LOG_ERR, "freopen()");
- } else {
- fclose(fp);
- fp = NULL;
- }
- if (!(fp = freopen("/dev/null", "w", stderr))) {
- syslog(LOG_ERR, "freopen()");
- } else {
- fclose(fp);
- fp = NULL;
- }
- if (!(fp = freopen("/dev/null", "r", stdin))) {
- syslog(LOG_ERR, "freopen()");
- } else {
- fclose(fp);
- fp = NULL;
- }
- #if defined (__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
- if (fork() > 0) {
- exit(0);
- #else
- if (daemon(1, 1)) {
- syslog(LOG_ERR, "daemon() failed!");
- #endif
- }
- else {
- /*
- * We switched PID when we forked.
- * To keep things nice and tity, lets move the
- * binary configuration file to the new directory.
- *
- * TODO: This process isn't ideal. But, the goal remains
- * that we don't need cmdline.o in the running chilli. We may
- * want to move away from gengetopt as it isn't exactly the most
- * flexible or light-weight.
- */
- mode_t process_mask = umask(0077);
- char file[128];
- char file2[128];
- int ok;
- pid_t new_pid = getpid();
- bstring bt = bfromcstr("");
- /*
- * Format the filename of the current (cpid) and new binconfig files.
- */
- chilli_binconfig(file, sizeof(file), cpid);
- chilli_binconfig(file2, sizeof(file2), new_pid);
- /*
- * Reset the binconfig option and save current setttings.
- */
- _options.binconfig = file2;
- ok = options_save(file2, bt);
- if (!ok) {
- syslog(LOG_ERR, "%s: could not save configuration options! [%s]", strerror(errno), file2);
- exit(1);
- }
- /*
- * Reset binconfig (since file2 is a local variable)
- */
- _options.binconfig = 0;
- umask(process_mask);
- bdestroy(bt);
- if (!options_binload(file2)) {
- syslog(LOG_ERR, "%s: could not reload configuration! [%s]", strerror(errno), file2);
- exit(1);
- }
- }
- }
- #ifdef LOG_NFACILITIES
- if (_options.logfacility < 0 || _options.logfacility > LOG_NFACILITIES)
- _options.logfacility= LOG_FAC(LOG_DAEMON);
- #endif
- closelog();
- if (_options.debug)
- syslog_options |= syslog_debug_options;
- openlog(syslog_ident, syslog_options, (_options.logfacility<<3));
- if (!_options.debug)
- setlogmask(LOG_UPTO(_options.loglevel));
- chilli_signals(&keep_going, &reload_config);
- #if XXX_IO_DAEMON
- pipe(ctrl_main_to_io);
- pipe(ctrl_io_to_main);
- pipe(pkt_main_to_io);
- pipe(pkt_io_to_main);
- chilli_fork = chilli_fork(CHILLI_PROC_DAEMON, "[chilli-io]");
- is_slave = chilli_fork > 0;
- if (chilli_fork < 0) perror("fork()");
- if (chilli_fork == 0)
- /* kick off io daemon */
- return chilli_io(ctrl_main_to_io[0],
- ctrl_io_to_main[1],
- pkt_main_to_io[0],
- pkt_io_to_main[1]);
- #endif
- chilli_pid = getpid();
- /* This has to be done after we have our final pid */
- log_pid((_options.pidfile && *_options.pidfile) ? _options.pidfile : DEFPIDFILE);
- #ifdef ENABLE_UAMANYIP
- /* setup IPv4LL/APIPA network ip and mask for uamanyip exception */
- inet_aton("169.254.0.0", &ipv4ll_ip);
- inet_aton("255.255.0.0", &ipv4ll_mask);
- #endif
- #ifdef ENABLE_SSDP
- ssdp.s_addr = inet_addr(SSDP_MCAST_ADDR);
- #endif
- syslog(LOG_INFO, "CoovaChilli %s. "
- "Copyright 2002-2005 Mondru AB. Licensed under GPL. "
- "Copyright 2006-2012 David Bird (Coova Technologies). "
- "Licensed under GPL. "
- "See http://coova.github.io/ for details.", VERSION);
- memset(&sctx, 0, sizeof(sctx));
- #ifdef HAVE_LIBRT
- memset(&startup_real, 0, sizeof(startup_real));
- memset(&startup_mono, 0, sizeof(startup_mono));
- if (clock_gettime(CLOCK_REALTIME, &startup_real) < 0) {
- syslog(LOG_ERR, "%s: getting startup (realtime) time", strerror(errno));
- }
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): clock realtime sec %ld nsec %ld", __FUNCTION__, __LINE__, startup_real.tv_sec, startup_real.tv_nsec);
- #ifdef CLOCK_MONOTONIC
- if (clock_gettime(CLOCK_MONOTONIC, &startup_mono) < 0) {
- syslog(LOG_ERR, "%s: getting startup (monotonic) time", strerror(errno));
- }
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): clock monotonic sec %ld nsec %ld", __FUNCTION__, __LINE__, startup_mono.tv_sec, startup_mono.tv_nsec);
- #endif
- #endif
- start_tick = mainclock_tick();
- /* Create a tunnel interface */
- if (tun_new(&tun)) {
- syslog(LOG_ERR, "Failed to create tun");
- exit(1);
- }
- tun_setaddr(tun,
- &_options.uamlisten,
- &_options.uamlisten,
- &_options.mask);
- tun_set_cb_ind(tun, cb_tun_ind);
- if (_options.ipup)
- tun_runscript(tun, _options.ipup, 0);
- /* Allocate ippool for dynamic IP address allocation */
- if (ippool_new(&ippool,
- _options.dynip,
- _options.dhcpstart,
- _options.dhcpend,
- _options.statip,
- _options.allowdyn,
- _options.allowstat)) {
- syslog(LOG_ERR, "Failed to allocate IP pool!");
- exit(1);
- }
- /* Create an instance of dhcp */
- if (dhcp_new(&dhcp,
- _options.max_clients,
- _options.dhcphashsize,
- _options.dhcpif,
- _options.dhcpusemac,
- _options.dhcpmac, 1,
- &_options.dhcplisten, _options.lease, 1,
- &_options.uamlisten, _options.uamport,
- _options.noc2c)) {
- syslog(LOG_ERR, "Failed to create dhcp listener on %s", _options.dhcpif);
- exit(1);
- }
- dhcp_set_cb_request(dhcp, cb_dhcp_request);
- dhcp_set_cb_connect(dhcp, cb_dhcp_connect);
- dhcp_set_cb_disconnect(dhcp, cb_dhcp_disconnect);
- dhcp_set_cb_data_ind(dhcp, cb_dhcp_data_ind);
- #ifdef ENABLE_EAPOL
- dhcp_set_cb_eap_ind(dhcp, cb_dhcp_eap_ind);
- #endif
- if (dhcp_set(dhcp,
- _options.ethers,
- (_options.debug & DEBUG_DHCP))) {
- syslog(LOG_ERR, "Failed to set DHCP parameters");
- exit(1);
- }
- /* Create an instance of radius */
- if (radius_new(&radius,
- &_options.radiuslisten,
- _options.coaport,
- _options.coanoipcheck, 1) ||
- radius_init_q(radius, _options.radiusqsize)) {
- syslog(LOG_ERR, "Failed to create radius");
- return -1;
- }
- radius_set(radius, dhcp ? dhcp->rawif[0].hwaddr : 0,
- (_options.debug & DEBUG_RADIUS));
- radius_set_cb_auth_conf(radius, cb_radius_auth_conf);
- #ifdef ENABLE_COA
- radius_set_cb_coa_ind(radius, cb_radius_coa_ind);
- #endif
- #ifdef ENABLE_RADPROXY
- radius_set_cb_ind(radius, cb_radius_ind);
- #endif
- if (_options.acct_update)
- radius_set_cb_acct_conf(radius, cb_radius_acct_conf);
- /* Initialise connections */
- initconn();
- /* Create an instance of redir */
- if (redir_new(&redir, &_options.uamlisten, _options.uamport,
- #ifdef ENABLE_UAMUIPORT
- _options.uamuiport
- #else
- 0
- #endif
- )) {
- syslog(LOG_ERR, "Failed to create redir");
- return -1;
- }
- if (!_options.redir && redir_listen(redir)) {
- syslog(LOG_ERR, "Failed to create redir listen");
- return -1;
- }
- if (redir_ipc(redir)) {
- syslog(LOG_ERR, "Failed to create redir IPC");
- return -1;
- }
- redir_set(redir, dhcp->rawif[0].hwaddr, (_options.debug));
- /* not really needed for chilliredir */
- redir_set_cb_getstate(redir, cb_redir_getstate);
- #ifdef ENABLE_CHILLIQUERY
- if (_options.cmdsocket) {
- cmdsock = cmdsock_init();
- } else {
- cmdsock = cmdsock_port_init();
- }
- if (cmdsock < 0) {
- syslog(LOG_ERR, "%s: Failed to initialize chilli query socket", strerror(errno));
- return -1;
- }
- #endif
- if (_options.radsec) {
- #ifdef ENABLE_CHILLIRADSEC
- launch_chilliradsec();
- #else
- syslog(LOG_ERR, "Feature is not supported; use --enable-chilliradsec");
- _options.radsec = 0;
- #endif
- } else if (_options.uamaaaurl) {
- #ifdef ENABLE_CHILLIPROXY
- launch_chilliproxy();
- #else
- syslog(LOG_ERR, "Feature is not supported; use --enable-chilliproxy");
- #endif
- }
- if (_options.redir) {
- #ifdef ENABLE_CHILLIREDIR
- launch_chilliredir();
- #else
- syslog(LOG_ERR, "Feature is not supported; use --enable-chilliredir");
- _options.redir = 0;
- #endif
- }
- #if(_debug_)
- if (_options.debug)
- syslog(LOG_DEBUG, "%s(%d): Waiting for client request...", __FUNCTION__, __LINE__);
- #endif
- /*
- * Administrative-User session
- */
- memset(&admin_session, 0, sizeof(admin_session));
- #ifdef ENABLE_BINSTATFILE
- if (loadstatus() != 0) /* Only indicate a fresh start-up if we didn't load keepalive sessions */
- #endif
- {
- #ifdef ENABLE_ACCOUNTING_ONOFF
- acct_req(ACCT_USER, &admin_session, RADIUS_STATUS_TYPE_ACCOUNTING_ON);
- #endif
- #ifdef HAVE_NETFILTER_COOVA
- if (_options.kname) {
- kmod_coova_clear();
- }
- #endif
- }
- if (_options.ethers && *_options.ethers && _options.macauth)
- macauth_reserved();
- if (_options.adminuser) {
- admin_session.is_adminsession = 1;
- strlcpy(admin_session.s_state.redir.username,
- _options.adminuser,
- sizeof(admin_session.s_state.redir.username));
- set_sessionid(&admin_session, 0);
- chilli_auth_radius(radius);
- }
- #ifdef ENABLE_UAMDOMAINFILE
- garden_load_domainfile();
- #endif
- #ifdef HAVE_PATRICIA
- garden_patricia_reload();
- #endif
- #ifdef ENABLE_LOCATION
- location_init();
- #endif
- /******************************************************************/
- /* Main select loop */
- /******************************************************************/
- if (_options.gid && setgid(_options.gid)) {
- syslog(LOG_ERR, "%d setgid(%d) failed while running with gid = %d",
- errno, _options.gid, getgid());
- }
- if (_options.uid && setuid(_options.uid)) {
- syslog(LOG_ERR, "%d setuid(%d) failed while running with uid = %d",
- errno, _options.uid, getuid());
- }
- if (net_select_init(&sctx))
- syslog(LOG_ERR, "%s: select init", strerror(errno));
- #ifdef ENABLE_MULTIROUTE
- tun->sctx = &sctx;
- for (i=0; i < tun->_interface_count; i++)
- net_select_reg(&sctx,
- (tun)->_interfaces[i].fd,
- SELECT_READ, (select_callback) tun_decaps,
- tun, i);
- #else
- net_select_reg(&sctx,
- (tun)->_tuntap.fd,
- SELECT_READ, (select_callback) tun_decaps,
- tun, 0);
- #endif
- net_select_reg(&sctx, selfpipe_init(),
- SELECT_READ, (select_callback)chilli_handle_signal,
- 0, 0);
- net_select_reg(&sctx, radius->fd, SELECT_READ,
- (select_callback)radius_decaps, radius, 0);
- #ifdef ENABLE_RADPROXY
- if (radius->proxyfd)
- net_select_reg(&sctx, radius->proxyfd, SELECT_READ,
- (select_callback)radius_proxy_ind, radius, 0);
- #endif
- #if defined(__linux__)
- net_select_reg(&sctx, dhcp->relayfd, SELECT_READ,
- (select_callback)dhcp_relay_decaps, dhcp, 0);
- for (i=0; i < MAX_RAWIF && dhcp->rawif[i].fd > 0; i++) {
- net_select_reg(&sctx, dhcp->rawif[i].fd, SELECT_READ,
- (select_callback)dhcp_decaps, dhcp, i);
- dhcp->rawif[i].sctx = &sctx;
- }
- #ifdef HAVE_NETFILTER_QUEUE
- if (dhcp->qif_in.fd && dhcp->qif_out.fd) {
- net_select_reg(&sctx, dhcp->qif_in.fd, SELECT_READ,
- (select_callback)dhcp_decaps, dhcp, 1);
- net_select_reg(&sctx, dhcp->qif_out.fd, SELECT_READ,
- (select_callback)dhcp_decaps, dhcp, 2);
- }
- #endif
- #elif defined (__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
- for (i=0; i < MAX_RAWIF && dhcp->rawif[i].fd > 0; i++) {
- net_select_reg(&sctx, dhcp->rawif[i].fd, SELECT_READ,
- (select_callback)dhcp_receive, dhcp, i);
- }
- #endif
- #ifdef USING_IPC_UNIX
- net_select_reg(&sctx, redir->msgfd, SELECT_READ,
- (select_callback)redir_msg, redir, 0);
- #endif
- if (!_options.redir) {
- net_select_reg(&sctx, redir->fd[0], SELECT_READ,
- (select_callback)redir_accept, redir, 0);
- net_select_reg(&sctx, redir->fd[1], SELECT_READ,
- (select_callback)redir_accept, redir, 1);
- }
- #ifdef ENABLE_MULTIROUTE
- if (!rtmon_init(&_rtmon, rtmon_proc_route)) {
- net_select_reg(&sctx, _rtmon.fd, SELECT_READ,
- (select_callback)rtmon_accept, &_rtmon, 0);
- }
- #endif
- #ifdef ENABLE_CHILLIQUERY
- net_select_reg(&sctx, cmdsock, SELECT_READ,
- (select_callback)cmdsock_accept, 0, cmdsock);
- #endif
- mainclock_tick();
- while (keep_going) {
- if (reload_config) {
- reload_options(argc, argv);
- reload_config = 0;
- /* Reinit DHCP parameters */
- if (dhcp) {
- dhcp_set(dhcp,
- _options.ethers,
- (_options.debug & DEBUG_DHCP));
- }
- /* Reinit RADIUS parameters */
- radius_set(radius, dhcp->rawif[0].hwaddr,
- (_options.debug & DEBUG_RADIUS));
- /* Reinit Redir parameters */
- redir_set(redir, dhcp->rawif[0].hwaddr, _options.debug);
- #ifdef HAVE_PATRICIA
- garden_patricia_reload();
- #endif
- #ifdef ENABLE_UAMDOMAINFILE
- garden_load_domainfile();
- #endif
- }
- if (do_interval) {
- reprocess_options(argc, argv);
- do_interval = 0;
- if (_options.adminuser)
- chilli_auth_radius(radius);
- }
- if (lastSecond != mainclock.tv_sec) {
- /*
- * Every second, more or less
- */
- radius_timeout(radius);
- if (dhcp)
- dhcp_timeout(dhcp);
- #ifdef ENABLE_LAYER3
- if (_options.layer3)
- session_timeout();
- #endif
- checkconn();
- lastSecond = mainclock.tv_sec;
- #ifdef ENABLE_CLUSTER
- dhcp_peer_update(0);
- #endif
- }
- if (net_select_prepare(&sctx))
- syslog(LOG_ERR, "%s: select prepare", strerror(errno));
- status = net_select(&sctx);
- mainclock_tick();
- #ifdef USING_IPC_MSG
- if ((msgresult =
- TEMP_FAILURE_RETRY(msgrcv(redir->msgid, (void *)&msg, sizeof(msg.mdata), 0, IPC_NOWAIT))) == -1) {
- if ((errno != EAGAIN) && (errno != ENOMSG))
- syslog(LOG_ERR, "%s: msgrcv() failed!", strerror(errno));
- }
- if (msgresult > 0)
- uam_msg(&msg);
- #endif
- if (status > 0) {
- net_run_selected(&sctx, status);
- }
- #ifdef USING_MMAP
- net_run(&dhcp->rawif[0]);
- #ifdef ENABLE_MULTIROUTE
- if (tun) {
- for (i=0; i < (tun)->_interface_count; i++) {
- net_run(&(tun)->_interfaces[i]);
- }
- }
- #endif
- #endif
- } /* while(keep_going) */
- syslog(LOG_INFO, "CoovaChilli shutting down");
- if (_options.seskeepalive) {
- #ifdef ENABLE_BINSTATFILE
- if (printstatus() != 0)
- syslog(LOG_ERR, "%s: could not save status file", strerror(errno));
- #else
- syslog(LOG_WARNING, "Not stopping sessions! seskeepalive should be used with compile option --enable-binstatusfile");
- #endif
- } else {
- killconn();
- #ifdef ENABLE_STATFILE
- if (printstatus() != 0)
- syslog(LOG_ERR, "%s: could not save status file", strerror(errno));
- #endif
- }
- child_killall(SIGTERM);
- if (_options.ipdown)
- tun_runscript(tun, _options.ipdown, 1);
- if (redir)
- redir_free(redir);
- if (radius)
- radius_free(radius);
- if (dhcp)
- dhcp_free(dhcp);
- if (tun)
- tun_free(tun);
- if (ippool)
- ippool_free(ippool);
- /*
- * Terminate not-so-nicely
- */
- #ifdef ENABLE_CHILLIQUERY
- cmdsock_shutdown();
- #endif
- #ifdef ENABLE_CHILLIREDIR
- if (redir_pid > 0) {
- kill(redir_pid, SIGTERM);
- }
- #endif
- #ifdef ENABLE_CHILLIPROXY
- if (proxy_pid > 0) {
- kill(proxy_pid, SIGTERM);
- }
- #endif
- #ifdef ENABLE_CHILLIRADSEC
- if (radsec_pid > 0) {
- kill(radsec_pid, SIGTERM);
- }
- #endif
- #ifdef ENABLE_UAMDOMAINFILE
- garden_free_domainfile();
- #endif
- selfpipe_finish();
- /* child_killall(SIGKILL);*/
- options_cleanup();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement