Branch data Line data Source code
1 : : /*
2 : : *****************************************************************************
3 : : *
4 : : * File: udp_server.c
5 : : *
6 : : * Purpose: Collect SPA packets via a UDP server.
7 : : *
8 : : * Fwknop is developed primarily by the people listed in the file 'AUTHORS'.
9 : : * Copyright (C) 2009-2014 fwknop developers and contributors. For a full
10 : : * list of contributors, see the file 'CREDITS'.
11 : : *
12 : : * License (GNU General Public License):
13 : : *
14 : : * This program is free software; you can redistribute it and/or
15 : : * modify it under the terms of the GNU General Public License
16 : : * as published by the Free Software Foundation; either version 2
17 : : * of the License, or (at your option) any later version.
18 : : *
19 : : * This program is distributed in the hope that it will be useful,
20 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 : : * GNU General Public License for more details.
23 : : *
24 : : * You should have received a copy of the GNU General Public License
25 : : * along with this program; if not, write to the Free Software
26 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 : : * USA
28 : : *
29 : : *****************************************************************************
30 : : */
31 : : #include "fwknopd_common.h"
32 : : #include "sig_handler.h"
33 : : #include "incoming_spa.h"
34 : : #include "log_msg.h"
35 : : #include "fw_util.h"
36 : : #include "utils.h"
37 : : #include <errno.h>
38 : :
39 : : #if HAVE_SYS_SOCKET_H
40 : : #include <sys/socket.h>
41 : : #endif
42 : : #if HAVE_ARPA_INET_H
43 : : #include <arpa/inet.h>
44 : : #endif
45 : : #if HAVE_NETDB
46 : : #include <netdb.h>
47 : : #endif
48 : :
49 : : #include <fcntl.h>
50 : : #include <sys/select.h>
51 : :
52 : : int
53 : 11 : run_udp_server(fko_srv_options_t *opts)
54 : : {
55 : : int s_sock, sfd_flags, selval, pkt_len;
56 : 11 : int is_err, s_timeout, rv=1, chk_rm_all=0;
57 : : int rules_chk_threshold;
58 : : fd_set sfd_set;
59 : : struct sockaddr_in saddr, caddr;
60 : : struct timeval tv;
61 : 11 : char sipbuf[MAX_IPV4_STR_LEN] = {0};
62 : 11 : char dgram_msg[MAX_SPA_PACKET_LEN+1] = {0};
63 : : unsigned short port;
64 : : socklen_t clen;
65 : :
66 : 11 : port = strtol_wrapper(opts->config[CONF_UDPSERV_PORT],
67 : : 1, MAX_PORT, NO_EXIT_UPON_ERR, &is_err);
68 [ - + ]: 11 : if(is_err != FKO_SUCCESS)
69 : : {
70 : 0 : log_msg(LOG_ERR, "[*] Invalid max UDPSERV_PORT value.");
71 : 0 : return -1;
72 : : }
73 : 11 : s_timeout = strtol_wrapper(opts->config[CONF_UDPSERV_SELECT_TIMEOUT],
74 : : 1, RCHK_MAX_UDPSERV_SELECT_TIMEOUT, NO_EXIT_UPON_ERR, &is_err);
75 [ - + ]: 11 : if(is_err != FKO_SUCCESS)
76 : : {
77 : 0 : log_msg(LOG_ERR, "[*] Invalid max UDPSERV_SELECT_TIMEOUT value.");
78 : 0 : return -1;
79 : : }
80 : 11 : rules_chk_threshold = strtol_wrapper(opts->config[CONF_RULES_CHECK_THRESHOLD],
81 : : 0, RCHK_MAX_RULES_CHECK_THRESHOLD, NO_EXIT_UPON_ERR, &is_err);
82 [ - + ]: 11 : if(is_err != FKO_SUCCESS)
83 : : {
84 : 0 : log_msg(LOG_ERR, "[*] invalid RULES_CHECK_THRESHOLD");
85 : 0 : clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
86 : : }
87 : :
88 : 11 : log_msg(LOG_INFO, "Kicking off UDP server to listen on port %i.", port);
89 : :
90 : : /* Now, let's make a UDP server
91 : : */
92 [ - + ]: 11 : if ((s_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
93 : : {
94 : 0 : log_msg(LOG_ERR, "run_udp_server: socket() failed: %s",
95 : 0 : strerror(errno));
96 : 0 : return -1;
97 : : }
98 : :
99 : : /* Make our main socket non-blocking so we don't have to be stuck on
100 : : * listening for incoming datagrams.
101 : : */
102 [ - + ]: 11 : if((sfd_flags = fcntl(s_sock, F_GETFL, 0)) < 0)
103 : : {
104 : 0 : log_msg(LOG_ERR, "run_udp_server: fcntl F_GETFL error: %s",
105 : 0 : strerror(errno));
106 : 0 : close(s_sock);
107 : 0 : return -1;
108 : : }
109 : :
110 : 11 : sfd_flags |= O_NONBLOCK;
111 : :
112 [ - + ]: 11 : if(fcntl(s_sock, F_SETFL, sfd_flags) < 0)
113 : : {
114 : 0 : log_msg(LOG_ERR, "run_udp_server: fcntl F_SETFL error setting O_NONBLOCK: %s",
115 : 0 : strerror(errno));
116 : 0 : close(s_sock);
117 : 0 : return -1;
118 : : }
119 : :
120 : : /* Construct local address structure */
121 : : memset(&saddr, 0x0, sizeof(saddr));
122 : 11 : saddr.sin_family = AF_INET; /* Internet address family */
123 : 11 : saddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
124 [ - + ]: 11 : saddr.sin_port = htons(port); /* Local port */
125 : :
126 : : /* Bind to the local address */
127 [ - + ]: 11 : if (bind(s_sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0)
128 : : {
129 : 0 : log_msg(LOG_ERR, "run_udp_server: bind() failed: %s",
130 : 0 : strerror(errno));
131 : 0 : close(s_sock);
132 : 0 : return -1;
133 : : }
134 : :
135 : : /* Initialize our signal handlers. You can check the return value for
136 : : * the number of signals that were *not* set. Those that were not set
137 : : * will be listed in the log/stderr output.
138 : : */
139 [ - + ]: 11 : if(set_sig_handlers() > 0)
140 : 0 : log_msg(LOG_ERR, "Errors encountered when setting signal handlers.");
141 : :
142 : 157 : FD_ZERO(&sfd_set);
143 : :
144 : : /* Now loop and receive SPA packets
145 : : */
146 : : while(1)
147 : : {
148 [ + + ]: 157 : if(sig_do_stop())
149 : : {
150 [ + - ]: 10 : if(opts->verbose)
151 : 10 : log_msg(LOG_INFO,
152 : : "udp_server: terminating signal received, will stop.");
153 : : break;
154 : : }
155 : :
156 : : /* Check for any expired firewall rules and deal with them.
157 : : */
158 [ + - ]: 147 : if(!opts->test)
159 : : {
160 [ + - ]: 147 : if(rules_chk_threshold > 0)
161 : : {
162 : 147 : opts->check_rules_ctr++;
163 [ + + ]: 147 : if ((opts->check_rules_ctr % rules_chk_threshold) == 0)
164 : : {
165 : 2 : chk_rm_all = 1;
166 : 2 : opts->check_rules_ctr = 0;
167 : : }
168 : : }
169 : 147 : check_firewall_rules(opts, chk_rm_all);
170 : 147 : chk_rm_all = 0;
171 : : }
172 : :
173 : : /* Initialize and setup the socket for select.
174 : : */
175 [ - + ][ # # ]: 147 : FD_SET(s_sock, &sfd_set);
176 : :
177 : : /* Set our select timeout to (500ms by default).
178 : : */
179 : 147 : tv.tv_sec = 0;
180 : 147 : tv.tv_usec = s_timeout;
181 : :
182 : 147 : selval = select(s_sock+1, &sfd_set, NULL, NULL, &tv);
183 : :
184 [ + + ]: 147 : if(selval == -1)
185 : : {
186 [ + - ]: 10 : if(errno == EINTR)
187 : : {
188 : : /* restart loop but only after we check for a terminating
189 : : * signal above in sig_do_stop()
190 : : */
191 : 10 : continue;
192 : : }
193 : : else
194 : : {
195 : 0 : log_msg(LOG_ERR, "run_udp_server: select error socket: %s",
196 : : strerror(errno));
197 : 0 : rv = -1;
198 : 0 : break;
199 : : }
200 : : }
201 : :
202 [ + + ]: 137 : if(selval == 0)
203 : 114 : continue;
204 : :
205 [ - + ][ # # ]: 23 : if(! FD_ISSET(s_sock, &sfd_set))
[ - + ]
206 : 0 : continue;
207 : :
208 : : /* If we make it here then there is a datagram to process
209 : : */
210 : 23 : clen = sizeof(caddr);
211 : :
212 : 46 : pkt_len = recvfrom(s_sock, dgram_msg, MAX_SPA_PACKET_LEN,
213 : : 0, (struct sockaddr *)&caddr, &clen);
214 : :
215 : 23 : dgram_msg[pkt_len] = 0x0;
216 : :
217 [ + - ]: 23 : if(opts->verbose)
218 : : {
219 : : memset(sipbuf, 0x0, MAX_IPV4_STR_LEN);
220 : 23 : inet_ntop(AF_INET, &(caddr.sin_addr.s_addr), sipbuf, MAX_IPV4_STR_LEN);
221 : 23 : log_msg(LOG_INFO, "udp_server: Got UDP datagram (%d bytes) from: %s",
222 : : pkt_len, sipbuf);
223 : : }
224 : :
225 : : /* Expect the data to not be too large
226 : : */
227 [ + - ]: 23 : if(pkt_len <= MAX_SPA_PACKET_LEN)
228 : : {
229 : : /* Copy the packet for SPA processing
230 : : */
231 : 23 : strlcpy((char *)opts->spa_pkt.packet_data, dgram_msg, pkt_len+1);
232 : 23 : opts->spa_pkt.packet_data_len = pkt_len;
233 : 23 : opts->spa_pkt.packet_proto = IPPROTO_UDP;
234 : 23 : opts->spa_pkt.packet_src_ip = caddr.sin_addr.s_addr;
235 : 23 : opts->spa_pkt.packet_dst_ip = saddr.sin_addr.s_addr;
236 [ - + ]: 23 : opts->spa_pkt.packet_src_port = ntohs(caddr.sin_port);
237 [ - + ]: 23 : opts->spa_pkt.packet_dst_port = ntohs(saddr.sin_port);
238 : :
239 : 23 : incoming_spa(opts);
240 : : }
241 : :
242 : : memset(dgram_msg, 0x0, sizeof(dgram_msg));
243 : :
244 : 23 : opts->packet_ctr += 1;
245 [ + - ][ + + ]: 23 : if(opts->foreground == 1 && opts->verbose > 2)
246 : 4 : log_msg(LOG_DEBUG, "run_udp_server() processed: %d packets",
247 : : opts->packet_ctr);
248 : :
249 [ + + ][ - + ]: 23 : if (opts->packet_ctr_limit && opts->packet_ctr >= opts->packet_ctr_limit)
250 : : {
251 : 1 : log_msg(LOG_WARNING,
252 : : "* Incoming packet count limit of %i reached",
253 : : opts->packet_ctr_limit
254 : : );
255 : 1 : break;
256 : : }
257 : :
258 : : } /* infinite while loop */
259 : :
260 : 11 : close(s_sock);
261 : 11 : return rv;
262 : : }
263 : :
264 : : /***EOF***/
|