2 * Copyright (C) 2006-2008 Stig Venaas <venaas@uninett.no>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
10 #include <sys/socket.h>
11 #include <netinet/in.h>
20 #include <sys/types.h>
21 #include <sys/select.h>
24 #include <arpa/inet.h>
27 #include <openssl/ssl.h>
31 #include "radsecproxy.h"
34 static int client4_sock = -1;
35 static int client6_sock = -1;
36 static struct queue *server_replyq = NULL;
38 /* exactly one of client and server must be non-NULL */
39 /* return who we received from in *client or *server */
40 /* return from in sa if not NULL */
41 unsigned char *radudpget(int s, struct client **client, struct server **server, struct sockaddr_storage *sa) {
43 unsigned char buf[4], *rad = NULL;
44 struct sockaddr_storage from;
45 struct sockaddr *fromcopy;
46 socklen_t fromlen = sizeof(from);
48 struct list_node *node;
58 if (select(s + 1, &readfds, NULL, NULL, NULL) < 1)
60 cnt = recvfrom(s, buf, 4, MSG_PEEK | MSG_TRUNC, (struct sockaddr *)&from, &fromlen);
62 debug(DBG_WARN, "radudpget: recv failed");
66 debug(DBG_WARN, "radudpget: length too small");
72 ? find_clconf(RAD_UDP, (struct sockaddr *)&from, NULL)
73 : find_srvconf(RAD_UDP, (struct sockaddr *)&from, NULL);
75 debug(DBG_WARN, "radudpget: got packet from wrong or unknown UDP peer %s, ignoring", addr2string((struct sockaddr *)&from, fromlen));
82 debug(DBG_WARN, "radudpget: length too small");
89 debug(DBG_ERR, "radudpget: malloc failed");
94 cnt = recv(s, rad, len, MSG_TRUNC);
95 debug(DBG_DBG, "radudpget: got %d bytes from %s", cnt, addr2string((struct sockaddr *)&from, fromlen));
98 debug(DBG_WARN, "radudpget: packet smaller than length field in radius header");
102 debug(DBG_DBG, "radudpget: packet was padded with %d bytes", cnt - len);
105 pthread_mutex_lock(p->lock);
106 for (node = list_first(p->clients); node; node = list_next(node))
107 if (addr_equal((struct sockaddr *)&from, ((struct client *)node->data)->addr))
110 *client = (struct client *)node->data;
111 pthread_mutex_unlock(p->lock);
114 fromcopy = addr_copy((struct sockaddr *)&from);
116 pthread_mutex_unlock(p->lock);
119 *client = addclient(p, 0);
122 pthread_mutex_unlock(p->lock);
125 (*client)->addr = fromcopy;
126 pthread_mutex_unlock(p->lock);
128 *server = p->servers;
136 int clientradputudp(struct server *server, unsigned char *rad) {
138 struct sockaddr_storage sa;
139 struct sockaddr *sap;
140 struct clsrvconf *conf = server->conf;
141 in_port_t *port = NULL;
145 if (*rad == RAD_Accounting_Request) {
146 sap = (struct sockaddr *)&sa;
147 memcpy(sap, conf->addrinfo->ai_addr, conf->addrinfo->ai_addrlen);
149 sap = conf->addrinfo->ai_addr;
151 switch (sap->sa_family) {
153 port = &((struct sockaddr_in *)sap)->sin_port;
156 port = &((struct sockaddr_in6 *)sap)->sin6_port;
162 if (*rad == RAD_Accounting_Request)
163 *port = htons(ntohs(*port) + 1);
165 if (sendto(server->sock, rad, len, 0, sap, conf->addrinfo->ai_addrlen) >= 0) {
166 debug(DBG_DBG, "clienradputudp: sent UDP of length %d to %s port %d", len, conf->host, ntohs(*port));
170 debug(DBG_WARN, "clientradputudp: send failed");
174 void *udpclientrd(void *arg) {
175 struct server *server;
181 buf = radudpget(*s, NULL, &server, NULL);
186 void *udpserverrd(void *arg) {
188 int *sp = (int *)arg;
193 sleep(5); /* malloc failed */
196 rq->buf = radudpget(*sp, &rq->from, NULL, &rq->fromsa);
197 rq->fromudpsock = *sp;
204 void *udpserverwr(void *arg) {
205 struct queue *replyq = (struct queue *)arg;
209 pthread_mutex_lock(&replyq->mutex);
210 while (!(reply = (struct reply *)list_shift(replyq->entries))) {
211 debug(DBG_DBG, "udp server writer, waiting for signal");
212 pthread_cond_wait(&replyq->cond, &replyq->mutex);
213 debug(DBG_DBG, "udp server writer, got signal");
215 pthread_mutex_unlock(&replyq->mutex);
217 if (sendto(reply->toudpsock, reply->buf, RADLEN(reply->buf), 0,
218 (struct sockaddr *)&reply->tosa, SOCKADDR_SIZE(reply->tosa)) < 0)
219 debug(DBG_WARN, "sendudp: send failed");
225 void addclientudp(struct client *client) {
226 client->replyq = server_replyq;
229 void addserverextraudp(struct clsrvconf *conf) {
230 switch (conf->addrinfo->ai_family) {
232 if (client4_sock < 0) {
233 client4_sock = bindtoaddr(getsrcprotores(RAD_UDP), AF_INET, 0, 1);
234 if (client4_sock < 0)
235 debugx(1, DBG_ERR, "addserver: failed to create client socket for server %s", conf->host);
237 conf->servers->sock = client4_sock;
240 if (client6_sock < 0) {
241 client6_sock = bindtoaddr(getsrcprotores(RAD_UDP), AF_INET6, 0, 1);
242 if (client6_sock < 0)
243 debugx(1, DBG_ERR, "addserver: failed to create client socket for server %s", conf->host);
245 conf->servers->sock = client6_sock;
248 debugx(1, DBG_ERR, "addserver: unsupported address family");
252 void initextraudp() {
253 pthread_t cl4th, cl6th, srvth;
255 if (client4_sock >= 0)
256 if (pthread_create(&cl4th, NULL, udpclientrd, (void *)&client4_sock))
257 debugx(1, DBG_ERR, "pthread_create failed");
258 if (client6_sock >= 0)
259 if (pthread_create(&cl6th, NULL, udpclientrd, (void *)&client6_sock))
260 debugx(1, DBG_ERR, "pthread_create failed");
262 if (find_clconf_type(RAD_UDP, NULL)) {
263 server_replyq = newqueue();
264 if (pthread_create(&srvth, NULL, udpserverwr, (void *)server_replyq))
265 debugx(1, DBG_ERR, "pthread_create failed");