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