diff options
Diffstat (limited to 'udp.c')
-rw-r--r-- | udp.c | 372 |
1 files changed, 0 insertions, 372 deletions
@@ -1,372 +0,0 @@ -/* - * Copyright (C) 2006-2009 Stig Venaas <venaas@uninett.no> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - */ - -#include <signal.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -#include <string.h> -#include <unistd.h> -#include <limits.h> -#ifdef SYS_SOLARIS9 -#include <fcntl.h> -#endif -#include <sys/time.h> -#include <sys/types.h> -#include <sys/select.h> -#include <ctype.h> -#include <sys/wait.h> -#include <arpa/inet.h> -#include <regex.h> -#include <pthread.h> -#include "list.h" -#include "hostport.h" -#include "radsecproxy.h" - -#ifdef RADPROT_UDP -#include "debug.h" -#include "util.h" - -static void setprotoopts(struct commonprotoopts *opts); -static char **getlistenerargs(); -void *udpserverrd(void *arg); -int clientradputudp(struct server *server, unsigned char *rad); -void addclientudp(struct client *client); -void addserverextraudp(struct clsrvconf *conf); -void udpsetsrcres(); -void initextraudp(); - -static const struct protodefs protodefs = { - "udp", - NULL, /* secretdefault */ - SOCK_DGRAM, /* socktype */ - "1812", /* portdefault */ - REQUEST_RETRY_COUNT, /* retrycountdefault */ - 10, /* retrycountmax */ - REQUEST_RETRY_INTERVAL, /* retryintervaldefault */ - 60, /* retryintervalmax */ - DUPLICATE_INTERVAL, /* duplicateintervaldefault */ - setprotoopts, /* setprotoopts */ - getlistenerargs, /* getlistenerargs */ - udpserverrd, /* listener */ - NULL, /* connecter */ - NULL, /* clientconnreader */ - clientradputudp, /* clientradput */ - addclientudp, /* addclient */ - addserverextraudp, /* addserverextra */ - udpsetsrcres, /* setsrcres */ - initextraudp /* initextra */ -}; - -static int client4_sock = -1; -static int client6_sock = -1; -static struct gqueue *server_replyq = NULL; - -static struct addrinfo *srcres = NULL; -static uint8_t handle; -static struct commonprotoopts *protoopts = NULL; - -const struct protodefs *udpinit(uint8_t h) { - handle = h; - return &protodefs; -} - -static void setprotoopts(struct commonprotoopts *opts) { - protoopts = opts; -} - -static char **getlistenerargs() { - return protoopts ? protoopts->listenargs : NULL; -} - -void udpsetsrcres() { - if (!srcres) - srcres = resolvepassiveaddrinfo(protoopts ? protoopts->sourcearg : NULL, NULL, protodefs.socktype); -} - -void removeudpclientfromreplyq(struct client *c) { - struct list_node *n; - struct request *r; - - /* lock the common queue and remove replies for this client */ - pthread_mutex_lock(&c->replyq->mutex); - for (n = list_first(c->replyq->entries); n; n = list_next(n)) { - r = (struct request *)n->data; - if (r->from == c) - r->from = NULL; - } - pthread_mutex_unlock(&c->replyq->mutex); -} - -static int addr_equal(struct sockaddr *a, struct sockaddr *b) { - switch (a->sa_family) { - case AF_INET: - return !memcmp(&((struct sockaddr_in*)a)->sin_addr, - &((struct sockaddr_in*)b)->sin_addr, - sizeof(struct in_addr)); - case AF_INET6: - return IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6*)a)->sin6_addr, - &((struct sockaddr_in6*)b)->sin6_addr); - default: - /* Must not reach */ - return 0; - } -} - -uint16_t port_get(struct sockaddr *sa) { - switch (sa->sa_family) { - case AF_INET: - return ntohs(((struct sockaddr_in *)sa)->sin_port); - case AF_INET6: - return ntohs(((struct sockaddr_in6 *)sa)->sin6_port); - } - return 0; -} - -/* exactly one of client and server must be non-NULL */ -/* return who we received from in *client or *server */ -/* return from in sa if not NULL */ -unsigned char *radudpget(int s, struct client **client, struct server **server, uint16_t *port) { - int cnt, len; - unsigned char buf[4], *rad = NULL; - struct sockaddr_storage from; - struct sockaddr *fromcopy; - socklen_t fromlen = sizeof(from); - struct clsrvconf *p; - struct list_node *node; - fd_set readfds; - struct client *c = NULL; - struct timeval now; - - for (;;) { - if (rad) { - free(rad); - rad = NULL; - } - FD_ZERO(&readfds); - FD_SET(s, &readfds); - if (select(s + 1, &readfds, NULL, NULL, NULL) < 1) - continue; - cnt = recvfrom(s, buf, 4, MSG_PEEK | MSG_TRUNC, (struct sockaddr *)&from, &fromlen); - if (cnt == -1) { - debug(DBG_WARN, "radudpget: recv failed"); - continue; - } - - p = client - ? find_clconf(handle, (struct sockaddr *)&from, NULL) - : find_srvconf(handle, (struct sockaddr *)&from, NULL); - if (!p) { - debug(DBG_WARN, "radudpget: got packet from wrong or unknown UDP peer %s, ignoring", addr2string((struct sockaddr *)&from)); - recv(s, buf, 4, 0); - continue; - } - - len = RADLEN(buf); - if (len < 20) { - debug(DBG_WARN, "radudpget: length too small"); - recv(s, buf, 4, 0); - continue; - } - - rad = malloc(len); - if (!rad) { - debug(DBG_ERR, "radudpget: malloc failed"); - recv(s, buf, 4, 0); - continue; - } - - cnt = recv(s, rad, len, MSG_TRUNC); - debug(DBG_DBG, "radudpget: got %d bytes from %s", cnt, addr2string((struct sockaddr *)&from)); - - if (cnt < len) { - debug(DBG_WARN, "radudpget: packet smaller than length field in radius header"); - continue; - } - if (cnt > len) - debug(DBG_DBG, "radudpget: packet was padded with %d bytes", cnt - len); - - if (client) { - *client = NULL; - pthread_mutex_lock(p->lock); - for (node = list_first(p->clients); node;) { - c = (struct client *)node->data; - node = list_next(node); - if (s != c->sock) - continue; - gettimeofday(&now, NULL); - if (!*client && addr_equal((struct sockaddr *)&from, c->addr)) { - c->expiry = now.tv_sec + 60; - *client = c; - } - if (c->expiry >= now.tv_sec) - continue; - - debug(DBG_DBG, "radudpget: removing expired client (%s)", addr2string(c->addr)); - removeudpclientfromreplyq(c); - c->replyq = NULL; /* stop removeclient() from removing common udp replyq */ - removelockedclient(c); - break; - } - if (!*client) { - fromcopy = addr_copy((struct sockaddr *)&from); - if (!fromcopy) { - pthread_mutex_unlock(p->lock); - continue; - } - c = addclient(p, 0); - if (!c) { - free(fromcopy); - pthread_mutex_unlock(p->lock); - continue; - } - c->sock = s; - c->addr = fromcopy; - gettimeofday(&now, NULL); - c->expiry = now.tv_sec + 60; - *client = c; - } - pthread_mutex_unlock(p->lock); - } else if (server) - *server = p->servers; - break; - } - if (port) - *port = port_get((struct sockaddr *)&from); - return rad; -} - -int clientradputudp(struct server *server, unsigned char *rad) { - size_t len; - struct clsrvconf *conf = server->conf; - struct addrinfo *ai; - - len = RADLEN(rad); - ai = ((struct hostportres *)list_first(conf->hostports)->data)->addrinfo; - if (sendto(server->sock, rad, len, 0, ai->ai_addr, ai->ai_addrlen) >= 0) { - debug(DBG_DBG, "clienradputudp: sent UDP of length %d to %s port %d", len, addr2string(ai->ai_addr), port_get(ai->ai_addr)); - return 1; - } - - debug(DBG_WARN, "clientradputudp: send failed"); - return 0; -} - -void *udpclientrd(void *arg) { - struct server *server; - unsigned char *buf; - int *s = (int *)arg; - - for (;;) { - server = NULL; - buf = radudpget(*s, NULL, &server, NULL); - replyh(server, buf); - } -} - -void *udpserverrd(void *arg) { - struct request *rq; - int *sp = (int *)arg; - - for (;;) { - rq = newrequest(); - if (!rq) { - sleep(5); /* malloc failed */ - continue; - } - rq->buf = radudpget(*sp, &rq->from, NULL, &rq->udpport); - rq->udpsock = *sp; - radsrv(rq); - } - free(sp); - return NULL; -} - -void *udpserverwr(void *arg) { - struct gqueue *replyq = (struct gqueue *)arg; - struct request *reply; - struct sockaddr_storage to; - - for (;;) { - pthread_mutex_lock(&replyq->mutex); - while (!(reply = (struct request *)list_shift(replyq->entries))) { - debug(DBG_DBG, "udp server writer, waiting for signal"); - pthread_cond_wait(&replyq->cond, &replyq->mutex); - debug(DBG_DBG, "udp server writer, got signal"); - } - /* do this with lock, udpserverrd may set from = NULL if from expires */ - if (reply->from) - memcpy(&to, reply->from->addr, SOCKADDRP_SIZE(reply->from->addr)); - pthread_mutex_unlock(&replyq->mutex); - if (reply->from) { - port_set((struct sockaddr *)&to, reply->udpport); - if (sendto(reply->udpsock, reply->replybuf, RADLEN(reply->replybuf), 0, (struct sockaddr *)&to, SOCKADDR_SIZE(to)) < 0) - debug(DBG_WARN, "udpserverwr: send failed"); - } - debug(DBG_DBG, "udpserverwr: refcount %d", reply->refcount); - freerq(reply); - } -} - -void addclientudp(struct client *client) { - client->replyq = server_replyq; -} - -void addserverextraudp(struct clsrvconf *conf) { - switch (((struct hostportres *)list_first(conf->hostports)->data)->addrinfo->ai_family) { - case AF_INET: - if (client4_sock < 0) { - client4_sock = bindtoaddr(srcres, AF_INET, 0, 1); - if (client4_sock < 0) - debugx(1, DBG_ERR, "addserver: failed to create client socket for server %s", conf->name); - } - conf->servers->sock = client4_sock; - break; - case AF_INET6: - if (client6_sock < 0) { - client6_sock = bindtoaddr(srcres, AF_INET6, 0, 1); - if (client6_sock < 0) - debugx(1, DBG_ERR, "addserver: failed to create client socket for server %s", conf->name); - } - conf->servers->sock = client6_sock; - break; - default: - debugx(1, DBG_ERR, "addserver: unsupported address family"); - } -} - -void initextraudp() { - pthread_t cl4th, cl6th, srvth; - - if (srcres) { - freeaddrinfo(srcres); - srcres = NULL; - } - - if (client4_sock >= 0) - if (pthread_create(&cl4th, NULL, udpclientrd, (void *)&client4_sock)) - debugx(1, DBG_ERR, "pthread_create failed"); - if (client6_sock >= 0) - if (pthread_create(&cl6th, NULL, udpclientrd, (void *)&client6_sock)) - debugx(1, DBG_ERR, "pthread_create failed"); - - if (find_clconf_type(handle, NULL)) { - server_replyq = newqueue(); - if (pthread_create(&srvth, NULL, udpserverwr, (void *)server_replyq)) - debugx(1, DBG_ERR, "pthread_create failed"); - } -} -#else -const struct protodefs *udpinit(uint8_t h) { - return NULL; -} -#endif - -/* Local Variables: */ -/* c-file-style: "stroustrup" */ -/* End: */ |