sending old reply when receiving duplicated message
[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, uint16_t *port) {
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     struct client *c = NULL;
51     
52     for (;;) {
53         if (rad) {
54             free(rad);
55             rad = NULL;
56         }
57         FD_ZERO(&readfds);
58         FD_SET(s, &readfds);
59         if (select(s + 1, &readfds, NULL, NULL, NULL) < 1)
60             continue;
61         cnt = recvfrom(s, buf, 4, MSG_PEEK | MSG_TRUNC, (struct sockaddr *)&from, &fromlen);
62         if (cnt == -1) {
63             debug(DBG_WARN, "radudpget: recv failed");
64             continue;
65         }
66         if (cnt < 20) {
67             debug(DBG_WARN, "radudpget: length too small");
68             recv(s, buf, 4, 0);
69             continue;
70         }
71         
72         p = client
73             ? find_clconf(RAD_UDP, (struct sockaddr *)&from, NULL)
74             : find_srvconf(RAD_UDP, (struct sockaddr *)&from, NULL);
75         if (!p) {
76             debug(DBG_WARN, "radudpget: got packet from wrong or unknown UDP peer %s, ignoring", addr2string((struct sockaddr *)&from));
77             recv(s, buf, 4, 0);
78             continue;
79         }
80         
81         len = RADLEN(buf);
82         if (len < 20) {
83             debug(DBG_WARN, "radudpget: length too small");
84             recv(s, buf, 4, 0);
85             continue;
86         }
87             
88         rad = malloc(len);
89         if (!rad) {
90             debug(DBG_ERR, "radudpget: malloc failed");
91             recv(s, buf, 4, 0);
92             continue;
93         }
94         
95         cnt = recv(s, rad, len, MSG_TRUNC);
96         debug(DBG_DBG, "radudpget: got %d bytes from %s", cnt, addr2string((struct sockaddr *)&from));
97
98         if (cnt < len) {
99             debug(DBG_WARN, "radudpget: packet smaller than length field in radius header");
100             continue;
101         }
102         if (cnt > len)
103             debug(DBG_DBG, "radudpget: packet was padded with %d bytes", cnt - len);
104
105         if (client) {
106             pthread_mutex_lock(p->lock);
107             for (node = list_first(p->clients); node; node = list_next(node)) {
108                 c = (struct client *)node->data;
109                 if (s == c->sock && addr_equal((struct sockaddr *)&from, c->addr))
110                     break;
111             }
112             if (!node) {
113                 fromcopy = addr_copy((struct sockaddr *)&from);
114                 if (!fromcopy) {
115                     pthread_mutex_unlock(p->lock);
116                     continue;
117                 }
118                 c = addclient(p, 0);
119                 if (!c) {
120                     free(fromcopy);
121                     pthread_mutex_unlock(p->lock);
122                     continue;
123                 }
124                 c->sock = s;
125                 c->addr = fromcopy;
126             }
127             *client = c;
128             pthread_mutex_unlock(p->lock);
129         } else if (server)
130             *server = p->servers;
131         break;
132     }
133     if (port)
134         *port = port_get((struct sockaddr *)&from);
135     return rad;
136 }
137
138 int clientradputudp(struct server *server, unsigned char *rad) {
139     size_t len;
140     struct sockaddr_storage sa;
141     struct sockaddr *sap;
142     struct clsrvconf *conf = server->conf;
143     uint16_t port;
144     
145     len = RADLEN(rad);
146     port = port_get(conf->addrinfo->ai_addr);
147     
148     if (*rad == RAD_Accounting_Request) {
149         sap = (struct sockaddr *)&sa;
150         memcpy(sap, conf->addrinfo->ai_addr, conf->addrinfo->ai_addrlen);
151         port_set(sap, ++port);
152     } else
153         sap = conf->addrinfo->ai_addr;
154
155     if (sendto(server->sock, rad, len, 0, sap, conf->addrinfo->ai_addrlen) >= 0) {
156         debug(DBG_DBG, "clienradputudp: sent UDP of length %d to %s port %d", len, conf->host, port);
157         return 1;
158     }
159
160     debug(DBG_WARN, "clientradputudp: send failed");
161     return 0;
162 }
163
164 void *udpclientrd(void *arg) {
165     struct server *server;
166     unsigned char *buf;
167     int *s = (int *)arg;
168     
169     for (;;) {
170         server = NULL;
171         buf = radudpget(*s, NULL, &server, NULL);
172         replyh(server, buf);
173     }
174 }
175
176 void *udpserverrd(void *arg) {
177     struct request *rq;
178     int *sp = (int *)arg;
179     
180     for (;;) {
181         rq = newrequest();
182         if (!rq) {
183             sleep(5); /* malloc failed */
184             continue;
185         }
186         rq->buf = radudpget(*sp, &rq->from, NULL, &rq->udpport);
187         rq->udpsock = *sp;
188         radsrv(rq);
189     }
190     free(sp);
191 }
192
193 void *udpserverwr(void *arg) {
194     struct queue *replyq = (struct queue *)arg;
195     struct request *reply;
196     struct sockaddr_storage to;
197     
198     for (;;) {
199         pthread_mutex_lock(&replyq->mutex);
200         while (!(reply = (struct request *)list_shift(replyq->entries))) {
201             debug(DBG_DBG, "udp server writer, waiting for signal");
202             pthread_cond_wait(&replyq->cond, &replyq->mutex);
203             debug(DBG_DBG, "udp server writer, got signal");
204         }
205         pthread_mutex_unlock(&replyq->mutex);
206
207         memcpy(&to, reply->from->addr, SOCKADDRP_SIZE(reply->from->addr));
208         port_set((struct sockaddr *)&to, reply->udpport);
209         if (sendto(reply->udpsock, reply->replybuf, RADLEN(reply->replybuf), 0, (struct sockaddr *)&to, SOCKADDR_SIZE(to)) < 0)
210             debug(DBG_WARN, "udpserverwr: send failed");
211         debug(DBG_DBG, "udpserverwr: refcount %d", reply->refcount);
212         freerq(reply);
213     }
214 }
215
216 void addclientudp(struct client *client) {
217     client->replyq = server_replyq;
218 }
219
220 void addserverextraudp(struct clsrvconf *conf) {
221     switch (conf->addrinfo->ai_family) {
222     case AF_INET:
223         if (client4_sock < 0) {
224             client4_sock = bindtoaddr(getsrcprotores(RAD_UDP), AF_INET, 0, 1);
225             if (client4_sock < 0)
226                 debugx(1, DBG_ERR, "addserver: failed to create client socket for server %s", conf->host);
227         }
228         conf->servers->sock = client4_sock;
229         break;
230     case AF_INET6:
231         if (client6_sock < 0) {
232             client6_sock = bindtoaddr(getsrcprotores(RAD_UDP), AF_INET6, 0, 1);
233             if (client6_sock < 0)
234                 debugx(1, DBG_ERR, "addserver: failed to create client socket for server %s", conf->host);
235         }
236         conf->servers->sock = client6_sock;
237         break;
238     default:
239         debugx(1, DBG_ERR, "addserver: unsupported address family");
240     }
241 }
242
243 void initextraudp() {
244     pthread_t cl4th, cl6th, srvth;
245     
246     if (client4_sock >= 0)
247         if (pthread_create(&cl4th, NULL, udpclientrd, (void *)&client4_sock))
248             debugx(1, DBG_ERR, "pthread_create failed");
249     if (client6_sock >= 0)
250         if (pthread_create(&cl6th, NULL, udpclientrd, (void *)&client6_sock))
251             debugx(1, DBG_ERR, "pthread_create failed");
252
253     if (find_clconf_type(RAD_UDP, NULL)) {
254         server_replyq = newqueue();
255         if (pthread_create(&srvth, NULL, udpserverwr, (void *)server_replyq))
256             debugx(1, DBG_ERR, "pthread_create failed");
257     }
258 }