Browse code

raw sockets: udp send will use now raw sockets if enabled

A raw socket, that will be used for sending, is now initialized on
startup. The operation can succeed only if sr is started as root
or with CAP_NET_RAW.
If the initialization fails and the raw sockets are forced on from
the config (udp4_raw = 1), ser won't start. If the raw socket are
in auto mode (udp4_raw = -1), sr will start, but with the raw
socket send part disabled (normal udp send will be used).

If the raw socket part is not disabled at startup, it can be
turned anytime on/off via the runtime cfg. framework.

Note: the raw socket send is supported only over ipv4 and for now
only on linux.

Andrei Pelinescu-Onciul authored on 15/06/2010 14:36:14
Showing 2 changed files
... ...
@@ -73,16 +73,15 @@
73 73
  * 2008-08-08  sctp support (andrei)
74 74
  * 2008-08-19  -l support for mmultihomed addresses/addresses lists
75 75
  *                (e.g. -l (eth0, 1.2.3.4, foo.bar) ) (andrei)
76
- *  2010-04-19 added daemon_status_fd pipe to communicate the parent process with
77
-               the main process in daemonize mode, so the parent process can return
78
-               the proper exit status code (ibc)
76
+ * 2010-04-19  added daemon_status_fd pipe to communicate the parent process
77
+ *              with the main process in daemonize mode, so the parent process
78
+ *              can return the proper exit status code (ibc)
79 79
  */
80 80
 
81
-/*!
82
- * \file
83
- * \brief SIP-router core :: 
84
- * \ingroup core
85
- * Module: \ref core
81
+/** intializations and startup.
82
+ * @file main.c
83
+ * @ingroup core
84
+ * Module: @ref core
86 85
  */
87 86
 
88 87
 /*! \defgroup core SIP-router core
... ...
@@ -148,6 +147,9 @@
148 148
 #include "nonsip_hooks.h"
149 149
 #include "ut.h"
150 150
 #include "signals.h"
151
+#ifdef USE_RAW_SOCKS
152
+#include "raw_sock.h"
153
+#endif /* USE_RAW_SOCKS */
151 154
 #ifdef USE_TCP
152 155
 #include "poll_types.h"
153 156
 #include "tcp_init.h"
... ...
@@ -439,6 +441,9 @@ struct socket_info* bind_address=0; /* pointer to the crt. proc.
439 439
 									 listening address*/
440 440
 struct socket_info* sendipv4; /* ipv4 socket to use when msg. comes from ipv6*/
441 441
 struct socket_info* sendipv6; /* same as above for ipv6 */
442
+#ifdef USE_RAW_SOCKS
443
+int raw_udp4_send_sock = -1; /* raw socket used for sending udp4 packets */
444
+#endif /* USE_RAW_SOCKS */
442 445
 #ifdef USE_TCP
443 446
 struct socket_info* sendipv4_tcp;
444 447
 struct socket_info* sendipv6_tcp;
... ...
@@ -1237,9 +1242,35 @@ int main_loop()
1237 1237
 		/* only one address, we ignore all the others */
1238 1238
 		if (udp_init(udp_listen)==-1) goto error;
1239 1239
 		bind_address=udp_listen;
1240
-		if (bind_address->address.af==AF_INET)
1240
+		if (bind_address->address.af==AF_INET) {
1241 1241
 			sendipv4=bind_address;
1242
-		else
1242
+#ifdef USE_RAW_SOCKS
1243
+		/* always try to have a raw socket opened if we are using ipv4 */
1244
+		raw_udp4_send_sock = raw_socket(IPPROTO_RAW, 0, 0, 1);
1245
+		if (raw_udp4_send_sock < 0) {
1246
+			if ( default_core_cfg.udp4_raw > 0) {
1247
+				/* force use raw socket failed */
1248
+				ERR("could not initialize raw udp send socket (ipv4):"
1249
+						" %s (%d)\n", strerror(errno), errno);
1250
+				if (errno == EPERM)
1251
+					ERR("could not initialize raw socket on startup"
1252
+						" due to inadequate permissions, please"
1253
+						" restart as root or with CAP_NET_RAW\n");
1254
+				goto error;
1255
+			}
1256
+			default_core_cfg.udp4_raw = 0; /* disabled */
1257
+		} else {
1258
+			register_fds(1);
1259
+			if (default_core_cfg.udp4_raw < 0) {
1260
+				/* auto-detect => use it */
1261
+				default_core_cfg.udp4_raw = 1; /* enabled */
1262
+				DBG("raw socket possible => turning it on\n");
1263
+			}
1264
+		}
1265
+#else
1266
+		default_core.cfg.udp4_raw = 0;
1267
+#endif /* USE_RAW_SOCKS */
1268
+		} else
1243 1269
 			sendipv6=bind_address;
1244 1270
 		if (udp_listen->next){
1245 1271
 			LOG(L_WARN, "WARNING: using only the first listen address"
... ...
@@ -1363,6 +1394,34 @@ int main_loop()
1363 1363
 			/* children_no per each socket */
1364 1364
 			cfg_register_child(children_no);
1365 1365
 		}
1366
+#ifdef USE_RAW_SOCKS
1367
+		/* always try to have a raw socket opened if we are using ipv4 */
1368
+		if (sendipv4) {
1369
+			raw_udp4_send_sock = raw_socket(IPPROTO_RAW, 0, 0, 1);
1370
+			if (raw_udp4_send_sock < 0) {
1371
+				if ( default_core_cfg.udp4_raw > 0) {
1372
+						/* force use raw socket failed */
1373
+						ERR("could not initialize raw udp send socket (ipv4):"
1374
+								" %s (%d)\n", strerror(errno), errno);
1375
+						if (errno == EPERM)
1376
+							ERR("could not initialize raw socket on startup"
1377
+								" due to inadequate permissions, please"
1378
+								" restart as root or with CAP_NET_RAW\n");
1379
+						goto error;
1380
+					}
1381
+					default_core_cfg.udp4_raw = 0; /* disabled */
1382
+			} else {
1383
+				register_fds(1);
1384
+				if (default_core_cfg.udp4_raw < 0) {
1385
+					/* auto-detect => use it */
1386
+					default_core_cfg.udp4_raw = 1; /* enabled */
1387
+					DBG("raw socket possible => turning it on\n");
1388
+				}
1389
+			}
1390
+		}
1391
+#else
1392
+		default_core_cfg.udp4_raw = 0;
1393
+#endif /* USE_RAW_SOCKS */
1366 1394
 #ifdef USE_SCTP
1367 1395
 		if (!sctp_disable){
1368 1396
 			for(si=sctp_listen; si; si=si->next){
... ...
@@ -41,14 +41,14 @@
41 41
  *  2007-08-28  disable/set MTU discover option for the udp sockets
42 42
  *               (in linux it's enabled by default which produces udp packets
43 43
  *                with the DF flag ser) (patch from hscholz)
44
+ *  2010-06-15  support for using raw sockets for sending (andrei)
44 45
  */
45 46
 
46 47
 
47
-/*!
48
- * \file
49
- * \brief SIP-router core :: 
50
- * \ingroup core
51
- * Module: \ref core
48
+/** udp send and loop-receive functions.
49
+ * @file udp_server.c
50
+ * @ingroup core
51
+ * Module: @ref core
52 52
  */
53 53
 
54 54
 #include <stdlib.h>
... ...
@@ -67,6 +67,7 @@
67 67
 
68 68
 
69 69
 #include "udp_server.h"
70
+#include "compiler_opt.h"
70 71
 #include "globals.h"
71 72
 #include "config.h"
72 73
 #include "dprint.h"
... ...
@@ -74,6 +75,10 @@
74 74
 #include "mem/mem.h"
75 75
 #include "ip_addr.h"
76 76
 #include "cfg/cfg_struct.h"
77
+#ifdef USE_RAW_SOCKS
78
+#include "raw_sock.h"
79
+#endif /* USE_RAW_SOCKS */
80
+
77 81
 
78 82
 #ifdef USE_STUN
79 83
   #include "ser_stun.h"
... ...
@@ -551,6 +556,9 @@ int udp_send(struct dest_info* dst, char *buf, unsigned len)
551 551
 	int n;
552 552
 	int tolen;
553 553
 	struct ip_addr ip; /* used only on error, for debugging */
554
+#ifdef USE_RAW_SOCKS
555
+	int mtu;
556
+#endif /* USE_RAW_SOCKS */
554 557
 
555 558
 #ifdef DBG_MSG_QA
556 559
 	/* aborts on error, does nothing otherwise */
... ...
@@ -559,24 +567,47 @@ int udp_send(struct dest_info* dst, char *buf, unsigned len)
559 559
 		abort();
560 560
 	}
561 561
 #endif
562
-
563
-	tolen=sockaddru_len(dst->to);
562
+#ifdef USE_RAW_SOCKS
563
+	if (likely( ! (raw_udp4_send_sock >= 0 &&
564
+					cfg_get(core, core_cfg, udp4_raw) &&
565
+					dst->send_sock->address.af == AF_INET) )) {
566
+#endif /* USE_RAW_SOCKS */
567
+		/* normal send over udp socket */
568
+		tolen=sockaddru_len(dst->to);
564 569
 again:
565
-	n=sendto(dst->send_sock->socket, buf, len, 0, &dst->to.s, tolen);
570
+		n=sendto(dst->send_sock->socket, buf, len, 0, &dst->to.s, tolen);
566 571
 #ifdef XL_DEBUG
567
-	LOG(L_INFO, "INFO: send status: %d\n", n);
572
+		LOG(L_INFO, "INFO: send status: %d\n", n);
568 573
 #endif
569
-	if (n==-1){
570
-		su2ip_addr(&ip, &dst->to);
571
-		LOG(L_ERR, "ERROR: udp_send: sendto(sock,%p,%u,0,%s:%d,%d): %s(%d)\n",
572
-				buf,len, ip_addr2a(&ip), su_getport(&dst->to), tolen,
573
-				strerror(errno),errno);
574
-		if (errno==EINTR) goto again;
575
-		if (errno==EINVAL) {
576
-			LOG(L_CRIT,"CRITICAL: invalid sendtoparameters\n"
577
-			"one possible reason is the server is bound to localhost and\n"
578
-			"attempts to send to the net\n");
574
+		if (unlikely(n==-1)){
575
+			su2ip_addr(&ip, &dst->to);
576
+			LOG(L_ERR, "ERROR: udp_send: sendto(sock,%p,%u,0,%s:%d,%d):"
577
+					" %s(%d)\n", buf,len, ip_addr2a(&ip),
578
+					su_getport(&dst->to), tolen, strerror(errno), errno);
579
+			if (errno==EINTR) goto again;
580
+			if (errno==EINVAL) {
581
+				LOG(L_CRIT,"CRITICAL: invalid sendtoparameters\n"
582
+				"one possible reason is the server is bound to localhost and\n"
583
+				"attempts to send to the net\n");
584
+			}
585
+		}
586
+#ifdef USE_RAW_SOCKS
587
+	} else {
588
+		/* send over a raw socket */
589
+		mtu = cfg_get(core, core_cfg, udp4_raw_mtu);
590
+raw_again:
591
+		n=raw_iphdr_udp4_send(raw_udp4_send_sock, buf, len,
592
+								&dst->send_sock->su,
593
+								&dst->to,
594
+								mtu);
595
+		if (unlikely(n==-1)){
596
+			su2ip_addr(&ip, &dst->to);
597
+			LOG(L_ERR, "ERROR: raw_udp4_send(sock,%p,%u,...,%s:%d,%d):"
598
+					" %s(%d)\n", buf,len, ip_addr2a(&ip),
599
+					su_getport(&dst->to), mtu, strerror(errno), errno);
600
+			if (errno==EINTR) goto raw_again;
579 601
 		}
580 602
 	}
603
+#endif /* USE_RAW_SOCKS */
581 604
 	return n;
582 605
 }