renamed some stuff, added client state for received rqs etc
[radsecproxy.git] / udp.c
1 /*
2  * Copyright (C) 2006-2008 Stig Venaas <venaas@uninett.no>
3  *
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.
7  */
8
9 #include <signal.h>
10 #include <sys/socket.h>
11 #include <netinet/in.h>
12 #include <netdb.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <limits.h>
16 #ifdef SYS_SOLARIS9
17 #include <fcntl.h>
18 #endif
19 #include <sys/time.h>
20 #include <sys/types.h>
21 #include <sys/select.h>
22 #include <ctype.h>
23 #include <sys/wait.h>
24 #include <arpa/inet.h>
25 #include <regex.h>
26 #include <pthread.h>
27 #include <openssl/ssl.h>
28 #include "debug.h"
29 #include "list.h"
30 #include "util.h"
31 #include "radsecproxy.h"
32 #include "tls.h"
33
34 static int client4_sock = -1;
35 static int client6_sock = -1;
36 static struct queue *server_replyq = NULL;
37
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) {
42     int cnt, len;
43     unsigned char buf[4], *rad = NULL;
44     struct sockaddr_storage from;
45     struct sockaddr *fromcopy;
46     socklen_t fromlen = sizeof(from);
47     struct clsrvconf *p;
48     struct list_node *node;
49     fd_set readfds;
50     
51     for (;;) {
52         if (rad) {
53             free(rad);
54             rad = NULL;
55         }
56         FD_ZERO(&readfds);
57         FD_SET(s, &readfds);
58         if (select(s + 1, &readfds, NULL, NULL, NULL) < 1)
59             continue;
60         cnt = recvfrom(s, buf, 4, MSG_PEEK | MSG_TRUNC, (struct sockaddr *)&from, &fromlen);
61         if (cnt == -1) {
62             debug(DBG_WARN, "radudpget: recv failed");
63             continue;
64         }
65         if (cnt < 20) {
66             debug(DBG_WARN, "radudpget: length too small");
67             recv(s, buf, 4, 0);
68             continue;
69         }
70         
71         p = client
72             ? find_clconf(RAD_UDP, (struct sockaddr *)&from, NULL)
73             : find_srvconf(RAD_UDP, (struct sockaddr *)&from, NULL);
74         if (!p) {
75             debug(DBG_WARN, "radudpget: got packet from wrong or unknown UDP peer %s, ignoring", addr2string((struct sockaddr *)&from, fromlen));
76             recv(s, buf, 4, 0);
77             continue;
78         }
79         
80         len = RADLEN(buf);
81         if (len < 20) {
82             debug(DBG_WARN, "radudpget: length too small");
83             recv(s, buf, 4, 0);
84             continue;
85         }
86             
87         rad = malloc(len);
88         if (!rad) {
89             debug(DBG_ERR, "radudpget: malloc failed");
90             recv(s, buf, 4, 0);
91             continue;
92         }
93         
94         cnt = recv(s, rad, len, MSG_TRUNC);
95         debug(DBG_DBG, "radudpget: got %d bytes from %s", cnt, addr2string((struct sockaddr *)&from, fromlen));
96
97         if (cnt < len) {
98             debug(DBG_WARN, "radudpget: packet smaller than length field in radius header");
99             continue;
100         }
101         if (cnt > len)
102             debug(DBG_DBG, "radudpget: packet was padded with %d bytes", cnt - len);
103
104         if (client) {
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))
108                     break;
109             if (node) {
110                 *client = (struct client *)node->data;
111                 pthread_mutex_unlock(p->lock);
112                 break;
113             }
114             fromcopy = addr_copy((struct sockaddr *)&from);
115             if (!fromcopy) {
116                 pthread_mutex_unlock(p->lock);
117                 continue;
118             }
119             *client = addclient(p, 0);
120             if (!*client) {
121                 free(fromcopy);
122                 pthread_mutex_unlock(p->lock);
123                 continue;
124             }
125             (*client)->addr = fromcopy;
126             pthread_mutex_unlock(p->lock);
127         } else if (server)
128             *server = p->servers;
129         break;
130     }
131     if (sa)
132         *sa = from;
133     return rad;
134 }
135
136 int clientradputudp(struct server *server, unsigned char *rad) {
137     size_t len;
138     struct sockaddr_storage sa;
139     struct sockaddr *sap;
140     struct clsrvconf *conf = server->conf;
141     in_port_t *port = NULL;
142     
143     len = RADLEN(rad);
144     
145     if (*rad == RAD_Accounting_Request) {
146         sap = (struct sockaddr *)&sa;
147         memcpy(sap, conf->addrinfo->ai_addr, conf->addrinfo->ai_addrlen);
148     } else
149         sap = conf->addrinfo->ai_addr;
150     
151     switch (sap->sa_family) {
152     case AF_INET:
153         port = &((struct sockaddr_in *)sap)->sin_port;
154         break;
155     case AF_INET6:
156         port = &((struct sockaddr_in6 *)sap)->sin6_port;
157         break;
158     default:
159         return 0;
160     }
161
162     if (*rad == RAD_Accounting_Request)
163         *port = htons(ntohs(*port) + 1);
164     
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));
167         return 1;
168     }
169
170     debug(DBG_WARN, "clientradputudp: send failed");
171     return 0;
172 }
173
174 void *udpclientrd(void *arg) {
175     struct server *server;
176     unsigned char *buf;
177     int *s = (int *)arg;
178     
179     for (;;) {
180         server = NULL;
181         buf = radudpget(*s, NULL, &server, NULL);
182         replyh(server, buf);
183     }
184 }
185
186 void *udpserverrd(void *arg) {
187     struct request *rq;
188     int *sp = (int *)arg;
189     
190     for (;;) {
191         rq = newrequest();
192         if (!rq) {
193             sleep(5); /* malloc failed */
194             continue;
195         }
196         rq->buf = radudpget(*sp, &rq->from, NULL, &rq->fromsa);
197         rq->fromudpsock = *sp;
198         radsrv(rq);
199         freerq(rq);
200     }
201     free(sp);
202 }
203
204 void *udpserverwr(void *arg) {
205     struct queue *replyq = (struct queue *)arg;
206     struct reply *reply;
207     
208     for (;;) {
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");
214         }
215         pthread_mutex_unlock(&replyq->mutex);
216
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");
220         free(reply->buf);
221         free(reply);
222     }
223 }
224
225 void addclientudp(struct client *client) {
226     client->replyq = server_replyq;
227 }
228
229 void addserverextraudp(struct clsrvconf *conf) {
230     switch (conf->addrinfo->ai_family) {
231     case AF_INET:
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);
236         }
237         conf->servers->sock = client4_sock;
238         break;
239     case AF_INET6:
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);
244         }
245         conf->servers->sock = client6_sock;
246         break;
247     default:
248         debugx(1, DBG_ERR, "addserver: unsupported address family");
249     }
250 }
251
252 void initextraudp() {
253     pthread_t cl4th, cl6th, srvth;
254     
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");
261
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");
266     }
267 }