[conntrack-tools] sync-mode: add unicast UDP support to propagate state-changes

Pablo Neira netfilter-cvslog-bounces at lists.netfilter.org
Fri Mar 13 14:26:08 CET 2009


Gitweb:		http://git.netfilter.org/cgi-bin/gitweb.cgi?p=conntrack-tools.git;a=commit;h=41e8560ea7c09533d03f523380c1cb5c62d87261
commit 41e8560ea7c09533d03f523380c1cb5c62d87261
Author:     Pablo Neira Ayuso <pablo at netfilter.org>
AuthorDate: Fri Mar 13 14:00:59 2009 +0100
Commit:     Pablo Neira Ayuso <pablo at netfilter.org>
CommitDate: Fri Mar 13 14:00:59 2009 +0100

    sync-mode: add unicast UDP support to propagate state-changes
    
    This patch adds support for unicast UDP to the channel
    infrastructure. With this patch, you can select UDP unicast to
    propagate state-changes instead of multicast.
    
    Signed-off-by: Pablo Neira Ayuso <pablo at netfilter.org>
       via  41e8560ea7c09533d03f523380c1cb5c62d87261 (commit)
      from  338d8fc2da19f5d6a75c339d9e6ecac43b68a1e4 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 41e8560ea7c09533d03f523380c1cb5c62d87261
Author: Pablo Neira Ayuso <pablo at netfilter.org>
Date:   Fri Mar 13 14:00:59 2009 +0100

    sync-mode: add unicast UDP support to propagate state-changes
    
    This patch adds support for unicast UDP to the channel
    infrastructure. With this patch, you can select UDP unicast to
    propagate state-changes instead of multicast.
    
    Signed-off-by: Pablo Neira Ayuso <pablo at netfilter.org>

-----------------------------------------------------------------------

 doc/sync/alarm/conntrackd.conf         |   52 ++++++-
 doc/sync/ftfw/conntrackd.conf          |   52 ++++++-
 doc/sync/notrack/conntrackd.conf       |   52 ++++++-
 include/Makefile.am                    |    2 +-
 include/channel.h                      |    9 +
 include/conntrackd.h                   |    1 +
 include/udp.h                          |   58 +++++++
 src/Makefile.am                        |    4 +-
 src/channel.c                          |    2 +
 src/{channel_mcast.c => channel_udp.c} |   70 +++++-----
 src/read_config_lex.l                  |   10 +-
 src/read_config_yy.y                   |  170 +++++++++++++++++++--
 src/udp.c                              |  261 ++++++++++++++++++++++++++++++++
 13 files changed, 676 insertions(+), 67 deletions(-)
 create mode 100644 include/udp.h
 copy src/{channel_mcast.c => channel_udp.c} (51%)
 create mode 100644 src/udp.c
This patch adds support for unicast UDP to the channel
infrastructure. With this patch, you can select UDP unicast to
propagate state-changes instead of multicast.

Signed-off-by: Pablo Neira Ayuso <pablo at netfilter.org>

diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf
index cefda00..9197db3 100644
--- a/doc/sync/alarm/conntrackd.conf
+++ b/doc/sync/alarm/conntrackd.conf
@@ -88,7 +88,7 @@ Sync {
 		# of the sender buffer. The default size is usually around
 		# ~100 KBytes which is fairly small for busy firewalls.
 		#
-		McastSndSocketBuffer 1249280
+		SndSocketBuffer 1249280
 
 		# The multicast receiver uses a buffer to enqueue the packets
 		# that the socket is pending to handle. The default size of this
@@ -100,7 +100,7 @@ Sync {
 		# the receiver buffer. The default size is usually around
 		# ~100 KBytes which is fairly small for busy firewalls.
 		#
-		McastRcvSocketBuffer 1249280
+		RcvSocketBuffer 1249280
 
 		# 
 		# Enable/Disable message checksumming. This is a good
@@ -124,10 +124,54 @@ Sync {
 	#	Group 3781
 	#	IPv4_interface 192.168.100.101
 	#	Interface eth3
-	#	# McastSndSocketBuffer 1249280
-	#	# McastRcvSocketBuffer 1249280
+	#	# SndSocketBuffer 1249280
+	#	# RcvSocketBuffer 1249280
 	#	Checksum on
 	# }
+
+	#
+	# You can use Unicast UDP instead of Multicast to propagate events.
+	# Note that you cannot use unicast UDP and Multicast at the same
+	# time, you can only select one.
+	# 
+	# UDP {
+		# 
+		# UDP address that this firewall uses to listen to events.
+		#
+		# IPv4_address 192.168.2.100
+
+		#
+		# Destination UDP address that receives events, ie. the other
+		# firewall's dedicated link address.
+		#
+		# IPv4_Destination_Address 192.168.2.101
+
+		#
+		# UDP port used
+		#
+		# Port 3780
+
+		#
+		# The name of the interface that you are going to use to
+		# send the synchronization messages.
+		#
+		# Interface eth2
+
+		# 
+		# The sender socket buffer size
+		#
+		# SndSocketBuffer 1249280
+
+		#
+		# The receiver socket buffer size
+		#
+		# RcvSocketBuffer 1249280
+
+		# 
+		# Enable/Disable message checksumming. 
+		#
+		# Checksum on
+	# }
 }
 
 #
diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf
index d7e4123..be78850 100644
--- a/doc/sync/ftfw/conntrackd.conf
+++ b/doc/sync/ftfw/conntrackd.conf
@@ -97,7 +97,7 @@ Sync {
 		# of the sender buffer. The default size is usually around
 		# ~100 KBytes which is fairly small for busy firewalls.
 		#
-		McastSndSocketBuffer 1249280
+		SndSocketBuffer 1249280
 
 		# The multicast receiver uses a buffer to enqueue the packets
 		# that the socket is pending to handle. The default size of this
@@ -109,7 +109,7 @@ Sync {
 		# the receiver buffer. The default size is usually around
 		# ~100 KBytes which is fairly small for busy firewalls.
 		#
-		McastRcvSocketBuffer 1249280
+		RcvSocketBuffer 1249280
 
 		# 
 		# Enable/Disable message checksumming. This is a good
@@ -133,10 +133,54 @@ Sync {
 	#	Group 3781
 	#	IPv4_interface 192.168.100.101
 	#	Interface eth3
-	#	# McastSndSocketBuffer 1249280
-	#	# McastRcvSocketBuffer 1249280
+	#	# SndSocketBuffer 1249280
+	#	# RcvSocketBuffer 1249280
 	#	Checksum on
 	# }
+
+	#
+	# You can use Unicast UDP instead of Multicast to propagate events.
+	# Note that you cannot use unicast UDP and Multicast at the same
+	# time, you can only select one.
+	# 
+	# UDP {
+		# 
+		# UDP address that this firewall uses to listen to events.
+		#
+		# IPv4_address 192.168.2.100
+
+		#
+		# Destination UDP address that receives events, ie. the other
+		# firewall's dedicated link address.
+		#
+		# IPv4_Destination_Address 192.168.2.101
+
+		#
+		# UDP port used
+		#
+		# Port 3780
+
+		#
+		# The name of the interface that you are going to use to
+		# send the synchronization messages.
+		#
+		# Interface eth2
+
+		# 
+		# The sender socket buffer size
+		#
+		# SndSocketBuffer 1249280
+
+		#
+		# The receiver socket buffer size
+		#
+		# RcvSocketBuffer 1249280
+
+		# 
+		# Enable/Disable message checksumming. 
+		#
+		# Checksum on
+	# }
 }
 
 #
diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf
index 884d536..173eab5 100644
--- a/doc/sync/notrack/conntrackd.conf
+++ b/doc/sync/notrack/conntrackd.conf
@@ -76,7 +76,7 @@ Sync {
 		# Note: This protocol is best effort, it is really recommended
 		# to increase the buffer size.
 		#
-		McastSndSocketBuffer 1249280
+		SndSocketBuffer 1249280
 
 		# The multicast receiver uses a buffer to enqueue the packets
 		# that the socket is pending to handle. The default size of this
@@ -90,7 +90,7 @@ Sync {
 		# Note: This protocol is best effort, it is really recommended
 		# to increase the buffer size.
 		#
-		McastRcvSocketBuffer 1249280
+		RcvSocketBuffer 1249280
 
 		#
 		# Enable/Disable message checksumming. This is a good
@@ -114,10 +114,54 @@ Sync {
 	#	Group 3781
 	#	IPv4_interface 192.168.100.101
 	#	Interface eth3
-	#	# McastSndSocketBuffer 1249280
-	#	# McastRcvSocketBuffer 1249280
+	#	# SndSocketBuffer 1249280
+	#	# RcvSocketBuffer 1249280
 	#	Checksum on
 	# }
+
+	#
+	# You can use Unicast UDP instead of Multicast to propagate events.
+	# Note that you cannot use unicast UDP and Multicast at the same
+	# time, you can only select one.
+	# 
+	# UDP {
+		# 
+		# UDP address that this firewall uses to listen to events.
+		#
+		# IPv4_address 192.168.2.100
+
+		#
+		# Destination UDP address that receives events, ie. the other
+		# firewall's dedicated link address.
+		#
+		# IPv4_Destination_Address 192.168.2.101
+
+		#
+		# UDP port used
+		#
+		# Port 3780
+
+		#
+		# The name of the interface that you are going to use to
+		# send the synchronization messages.
+		#
+		# Interface eth2
+
+		# 
+		# The sender socket buffer size
+		#
+		# SndSocketBuffer 1249280
+
+		#
+		# The receiver socket buffer size
+		#
+		# RcvSocketBuffer 1249280
+
+		# 
+		# Enable/Disable message checksumming. 
+		#
+		# Checksum on
+	# }
 }
 
 #
diff --git a/include/Makefile.am b/include/Makefile.am
index 0265620..f02ce89 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -1,6 +1,6 @@
 
 noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \
-		 sync.h conntrackd.h local.h \
+		 sync.h conntrackd.h local.h udp.h \
 		 debug.h log.h hash.h mcast.h conntrack.h \
 		 network.h filter.h queue.h vector.h cidr.h \
 		 traffic_stats.h netlink.h fds.h event.h bitops.h channel.h
diff --git a/include/channel.h b/include/channel.h
index ac1a93c..42534e0 100644
--- a/include/channel.h
+++ b/include/channel.h
@@ -2,12 +2,15 @@
 #define _CHANNEL_H_
 
 #include "mcast.h"
+#include "udp.h"
 
 struct channel;
 struct nethdr;
 
 enum {
+	CHANNEL_NONE,
 	CHANNEL_MCAST,
+	CHANNEL_UDP,
 	CHANNEL_MAX,
 };
 
@@ -16,12 +19,18 @@ struct mcast_channel {
 	struct mcast_sock *server;
 };
 
+struct udp_channel {
+	struct udp_sock *client;
+	struct udp_sock *server;
+};
+
 #define CHANNEL_F_DEFAULT	(1 << 0)
 #define CHANNEL_F_BUFFERED	(1 << 1)
 #define CHANNEL_F_MAX		(1 << 2)
 
 union channel_type_conf {
 	struct mcast_conf mcast;
+	struct udp_conf udp;
 };
 
 struct channel_conf {
diff --git a/include/conntrackd.h b/include/conntrackd.h
index cfb1ac5..f30a094 100644
--- a/include/conntrackd.h
+++ b/include/conntrackd.h
@@ -74,6 +74,7 @@ struct ct_conf {
 	int hashsize;			/* hashtable size */
 	int channel_num;
 	int channel_default;
+	int channel_type_global;
 	struct channel_conf channel[MULTICHANNEL_MAX];
 	struct local_conf local;	/* unix socket facilities */
 	int nice;
diff --git a/include/udp.h b/include/udp.h
new file mode 100644
index 0000000..02b8af1
--- /dev/null
+++ b/include/udp.h
@@ -0,0 +1,58 @@
+#ifndef _UDP_H_
+#define _UDP_H_
+
+#include <stdint.h>
+#include <netinet/in.h>
+
+struct udp_conf {
+	int ipproto;
+	int reuseaddr;
+	int checksum;
+	unsigned short port;
+	union {
+		struct in_addr inet_addr;
+		struct in6_addr inet_addr6;
+	} server;
+	union {
+		struct in_addr inet_addr;
+		struct in6_addr inet_addr6;
+	} client;
+	int sndbuf;
+	int rcvbuf;
+};
+
+struct udp_stats {
+	uint64_t bytes;
+	uint64_t messages;
+	uint64_t error;
+};
+
+struct udp_sock {
+	int fd;
+	union {
+		struct sockaddr_in ipv4;
+		struct sockaddr_in6 ipv6;
+	} addr;
+	socklen_t sockaddr_len;
+	struct udp_stats stats;
+};
+
+struct udp_sock *udp_server_create(struct udp_conf *conf);
+void udp_server_destroy(struct udp_sock *m);
+
+struct udp_sock *udp_client_create(struct udp_conf *conf);
+void udp_client_destroy(struct udp_sock *m);
+
+ssize_t udp_send(struct udp_sock *m, const void *data, int size);
+ssize_t udp_recv(struct udp_sock *m, void *data, int size);
+
+int udp_get_fd(struct udp_sock *m);
+
+int udp_snprintf_stats(char *buf, size_t buflen, char *ifname,
+		       struct udp_stats *s, struct udp_stats *r);
+
+int udp_snprintf_stats2(char *buf, size_t buflen, const char *ifname,
+			const char *status, int active,
+			struct udp_stats *s, struct udp_stats *r);
+
+#endif
diff --git a/src/Makefile.am b/src/Makefile.am
index 54cfda4..667040c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,7 +11,7 @@ conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp
 conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@
 
 conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \
-		    local.c log.c mcast.c netlink.c vector.c \
+		    local.c log.c mcast.c udp.c netlink.c vector.c \
 		    filter.c fds.c event.c \
 		    cache.c cache_iterators.c \
 		    cache_timer.c cache_wt.c \
@@ -19,7 +19,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \
 		    traffic_stats.c stats-mode.c \
 		    network.c cidr.c \
 		    build.c parse.c \
-		    channel.c multichannel.c channel_mcast.c \
+		    channel.c multichannel.c channel_mcast.c channel_udp.c \
 		    read_config_yy.y read_config_lex.l
 
 # yacc and lex generate dirty code
diff --git a/src/channel.c b/src/channel.c
index 733fd03..255026a 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -19,10 +19,12 @@
 
 static struct channel_ops *ops[CHANNEL_MAX];
 extern struct channel_ops channel_mcast;
+extern struct channel_ops channel_udp;
 
 void channel_init(void)
 {
 	ops[CHANNEL_MCAST] = &channel_mcast;
+	ops[CHANNEL_UDP] = &channel_udp;
 }
 
 #define HEADERSIZ 28 /* IP header (20 bytes) + UDP header 8 (bytes) */
diff --git a/src/channel_udp.c b/src/channel_udp.c
new file mode 100644
index 0000000..1c15b47
--- /dev/null
+++ b/src/channel_udp.c
@@ -0,0 +1,123 @@
+/*
+ * (C) 2009 by Pablo Neira Ayuso <pablo at netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <stdlib.h>
+#include <libnfnetlink/libnfnetlink.h>
+
+#include "channel.h"
+#include "udp.h"
+
+static void
+*channel_udp_open(void *conf)
+{
+	struct udp_channel *m;
+	struct udp_conf *c = conf;
+
+	m = calloc(sizeof(struct udp_channel), 1);
+	if (m == NULL)
+		return NULL;
+
+	m->client = udp_client_create(c);
+	if (m->client == NULL) {
+		free(m);
+		return NULL;
+	}
+
+	m->server = udp_server_create(c);
+	if (m->server == NULL) {
+		udp_client_destroy(m->client);
+		free(m);
+		return NULL;
+	}
+	return m;
+}
+
+static int
+channel_udp_send(void *channel, const void *data, int len)
+{
+	struct udp_channel *m = channel;
+	return udp_send(m->client, data, len);
+}
+
+static int
+channel_udp_recv(void *channel, char *buf, int size)
+{
+	struct udp_channel *m = channel;
+	return udp_recv(m->server, buf, size);
+}
+
+static void
+channel_udp_close(void *channel)
+{
+	struct udp_channel *m = channel;
+	udp_client_destroy(m->client);
+	udp_server_destroy(m->server);
+	free(m);
+}
+
+static int
+channel_udp_get_fd(void *channel)
+{
+	struct udp_channel *m = channel;
+	return udp_get_fd(m->server);
+}
+
+static void
+channel_udp_stats(struct channel *c, int fd)
+{
+	struct udp_channel *m = c->data;
+	char ifname[IFNAMSIZ], buf[512];
+	int size;
+
+	if_indextoname(c->channel_ifindex, ifname);
+	size = udp_snprintf_stats(buf, sizeof(buf), ifname,
+				    &m->client->stats, &m->server->stats);
+	send(fd, buf, size, 0);
+}
+
+static void
+channel_udp_stats_extended(struct channel *c, int active,
+			     struct nlif_handle *h, int fd)
+{
+	struct udp_channel *m = c->data;
+	char ifname[IFNAMSIZ], buf[512];
+	const char *status;
+	unsigned int flags;
+	int size;
+
+	if_indextoname(c->channel_ifindex, ifname);
+	nlif_get_ifflags(h, c->channel_ifindex, &flags);
+	/* 
+	 * IFF_UP shows administrative status
+	 * IFF_RUNNING shows carrier status
+	 */
+	if (flags & IFF_UP) {
+		if (!(flags & IFF_RUNNING))
+			status = "NO-CARRIER";
+		else
+			status = "RUNNING";
+	} else {
+		status = "DOWN";
+	}
+	size = udp_snprintf_stats2(buf, sizeof(buf),
+				     ifname, status, active,
+				     &m->client->stats,
+				     &m->server->stats);
+	send(fd, buf, size, 0);
+}
+
+struct channel_ops channel_udp = {
+	.open		= channel_udp_open,
+	.close		= channel_udp_close,
+	.send		= channel_udp_send,
+	.recv		= channel_udp_recv,
+	.get_fd		= channel_udp_get_fd,
+	.stats		= channel_udp_stats,
+	.stats_extended = channel_udp_stats_extended,
+};
diff --git a/src/read_config_lex.l b/src/read_config_lex.l
index d75e299..44ccf0b 100644
--- a/src/read_config_lex.l
+++ b/src/read_config_lex.l
@@ -58,11 +58,14 @@ notrack		[N|n][O|o][T|t][R|r][A|a][C|c][K|k]
 "UNIX"				{ return T_UNIX; }
 "IPv4_address"			{ return T_IPV4_ADDR; }
 "IPv6_address"			{ return T_IPV6_ADDR; }
+"IPv4_Destination_Address"	{ return T_IPV4_DEST_ADDR; }
+"IPv6_Destination_Address"	{ return T_IPV6_DEST_ADDR; }
 "IPv4_interface"		{ return T_IPV4_IFACE; }
 "IPv6_interface"		{ return T_IPV6_IFACE; }
 "Interface"			{ return T_IFACE; }
 "Port"				{ return T_PORT; }
 "Multicast"			{ return T_MULTICAST; }
+"UDP"				{ return T_UDP; }
 "HashSize"			{ return T_HASHSIZE; }
 "RefreshTime"			{ return T_REFRESH; }
 "CacheTimeout"			{ return T_EXPIRE; }
@@ -75,6 +78,7 @@ notrack		[N|n][O|o][T|t][R|r][A|a][C|c][K|k]
 "StripNAT"			{ return T_STRIP_NAT; }
 "Backlog"			{ return T_BACKLOG; }
 "Group"				{ return T_GROUP; }
+"Port"				{ return T_PORT; }
 "LogFile"			{ return T_LOG; }
 "Syslog"			{ return T_SYSLOG; }
 "LockFile"			{ return T_LOCK; }
@@ -109,8 +113,10 @@ notrack		[N|n][O|o][T|t][R|r][A|a][C|c][K|k]
 "LISTEN"			{ return T_LISTEN; }
 "LogFileBufferSize"		{ return T_STAT_BUFFER_SIZE; }
 "DestroyTimeout"		{ return T_DESTROY_TIMEOUT; }
-"McastSndSocketBuffer"		{ return T_MCAST_SNDBUFF; }
-"McastRcvSocketBuffer"		{ return T_MCAST_RCVBUFF; }
+"McastSndSocketBuffer"		{ return T_SNDBUFF; /* deprecated */ }
+"McastRcvSocketBuffer"		{ return T_RCVBUFF; /* deprecated */ }
+"SndSocketBuffer"		{ return T_SNDBUFF; }
+"RcvSocketBuffer"		{ return T_RCVBUFF; }
 "Filter"			{ return T_FILTER; }
 "Protocol"			{ return T_PROTOCOL; }
 "Address"			{ return T_ADDRESS; }
diff --git a/src/read_config_yy.y b/src/read_config_yy.y
index b3a2640..cfcd574 100644
--- a/src/read_config_yy.y
+++ b/src/read_config_yy.y
@@ -38,7 +38,7 @@ struct ct_conf conf;
 
 static void __kernel_filter_start(void);
 static void __kernel_filter_add_state(int value);
-static void __max_mcast_dedicated_links_reached(void);
+static void __max_dedicated_links_reached(void);
 %}
 
 %union {
@@ -58,10 +58,10 @@ static void __max_mcast_dedicated_links_reached(void);
 %token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT 
 %token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN
 %token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE T_DESTROY_TIMEOUT
-%token T_MCAST_RCVBUFF T_MCAST_SNDBUFF T_NOTRACK T_POLL_SECS
+%token T_RCVBUFF T_SNDBUFF T_NOTRACK T_POLL_SECS
 %token T_FILTER T_ADDRESS T_PROTOCOL T_STATE T_ACCEPT T_IGNORE
 %token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT T_DEFAULT
-%token T_NETLINK_OVERRUN_RESYNC T_NICE
+%token T_NETLINK_OVERRUN_RESYNC T_NICE T_IPV4_DEST_ADDR T_IPV6_DEST_ADDR
 
 %token <string> T_IP T_PATH_VAL
 %token <val> T_NUMBER
@@ -256,6 +256,13 @@ ignore_traffic_option : T_IPV6_ADDR T_IP
 
 multicast_line : T_MULTICAST '{' multicast_options '}'
 {
+	if (conf.channel_type_global != CHANNEL_NONE &&
+	    conf.channel_type_global != CHANNEL_MCAST) {
+		fprintf(stderr, "ERROR: Cannot use `Multicast' with other "
+				"dedicated link protocols!\n");
+		exit(EXIT_FAILURE);
+	}
+	conf.channel_type_global = CHANNEL_MCAST;
 	conf.channel[conf.channel_num].channel_type = CHANNEL_MCAST;
 	conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED;
 	conf.channel_num++;
@@ -263,6 +270,13 @@ multicast_line : T_MULTICAST '{' multicast_options '}'
 
 multicast_line : T_MULTICAST T_DEFAULT '{' multicast_options '}'
 {
+	if (conf.channel_type_global != CHANNEL_NONE &&
+	    conf.channel_type_global != CHANNEL_MCAST) {
+		fprintf(stderr, "ERROR: Cannot use `Multicast' with other "
+				"dedicated link protocols!\n");
+		exit(EXIT_FAILURE);
+	}
+	conf.channel_type_global = CHANNEL_MCAST;
 	conf.channel[conf.channel_num].channel_type = CHANNEL_MCAST;
 	conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT |
 						       CHANNEL_F_BUFFERED;
@@ -275,7 +289,7 @@ multicast_options :
 
 multicast_option : T_IPV4_ADDR T_IP
 {
-	__max_mcast_dedicated_links_reached();
+	__max_dedicated_links_reached();
 
 	if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.in)) {
 		fprintf(stderr, "%s is not a valid IPv4 address\n", $2);
@@ -294,7 +308,7 @@ multicast_option : T_IPV4_ADDR T_IP
 
 multicast_option : T_IPV6_ADDR T_IP
 {
-	__max_mcast_dedicated_links_reached();
+	__max_dedicated_links_reached();
 
 #ifdef HAVE_INET_PTON_IPV6
 	if (inet_pton(AF_INET6, $2,
@@ -333,7 +347,7 @@ multicast_option : T_IPV6_ADDR T_IP
 
 multicast_option : T_IPV4_IFACE T_IP
 {
-	__max_mcast_dedicated_links_reached();
+	__max_dedicated_links_reached();
 
 	if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.ifa)) {
 		fprintf(stderr, "%s is not a valid IPv4 address\n", $2);
@@ -359,7 +373,7 @@ multicast_option : T_IFACE T_STRING
 {
 	unsigned int idx;
 
-	__max_mcast_dedicated_links_reached();
+	__max_dedicated_links_reached();
 
 	strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ);
 	strncpy(conf.channel[conf.channel_num].u.mcast.iface, $2, IFNAMSIZ);
@@ -385,34 +399,159 @@ multicast_option : T_BACKLOG T_NUMBER
 
 multicast_option : T_GROUP T_NUMBER
 {
-	__max_mcast_dedicated_links_reached();
+	__max_dedicated_links_reached();
 	conf.channel[conf.channel_num].u.mcast.port = $2;
 };
 
-multicast_option: T_MCAST_SNDBUFF T_NUMBER
+multicast_option: T_SNDBUFF T_NUMBER
 {
-	__max_mcast_dedicated_links_reached();
+	__max_dedicated_links_reached();
 	conf.channel[conf.channel_num].u.mcast.sndbuf = $2;
 };
 
-multicast_option: T_MCAST_RCVBUFF T_NUMBER
+multicast_option: T_RCVBUFF T_NUMBER
 {
-	__max_mcast_dedicated_links_reached();
+	__max_dedicated_links_reached();
 	conf.channel[conf.channel_num].u.mcast.rcvbuf = $2;
 };
 
 multicast_option: T_CHECKSUM T_ON 
 {
-	__max_mcast_dedicated_links_reached();
+	__max_dedicated_links_reached();
 	conf.channel[conf.channel_num].u.mcast.checksum = 0;
 };
 
 multicast_option: T_CHECKSUM T_OFF
 {
-	__max_mcast_dedicated_links_reached();
+	__max_dedicated_links_reached();
 	conf.channel[conf.channel_num].u.mcast.checksum = 1;
 };
 
+udp_line : T_UDP '{' udp_options '}'
+{
+	if (conf.channel_type_global != CHANNEL_NONE &&
+	    conf.channel_type_global != CHANNEL_UDP) {
+		fprintf(stderr, "ERROR: Cannot use `UDP' with other "
+				"dedicated link protocols!\n");
+		exit(EXIT_FAILURE);
+	}
+	conf.channel_type_global = CHANNEL_UDP;
+	conf.channel[conf.channel_num].channel_type = CHANNEL_UDP;
+	conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED;
+	conf.channel_num++;
+};
+
+udp_line : T_UDP T_DEFAULT '{' udp_options '}'
+{
+	if (conf.channel_type_global != CHANNEL_NONE &&
+	    conf.channel_type_global != CHANNEL_UDP) {
+		fprintf(stderr, "ERROR: Cannot use `UDP' with other "
+				"dedicated link protocols!\n");
+		exit(EXIT_FAILURE);
+	}
+	conf.channel_type_global = CHANNEL_UDP;
+	conf.channel[conf.channel_num].channel_type = CHANNEL_UDP;
+	conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT |
+						       CHANNEL_F_BUFFERED;
+	conf.channel_default = conf.channel_num;
+	conf.channel_num++;
+};
+
+udp_options :
+	    | udp_options udp_option;
+
+udp_option : T_IPV4_ADDR T_IP
+{
+	__max_dedicated_links_reached();
+
+	if (!inet_aton($2, &conf.channel[conf.channel_num].u.udp.server)) {
+		fprintf(stderr, "%s is not a valid IPv4 address\n", $2);
+		break;
+	}
+	conf.channel[conf.channel_num].u.udp.ipproto = AF_INET;
+};
+
+udp_option : T_IPV6_ADDR T_IP
+{
+	__max_dedicated_links_reached();
+
+#ifdef HAVE_INET_PTON_IPV6
+	if (inet_pton(AF_INET6, $2,
+		      &conf.channel[conf.channel_num].u.udp.server) <= 0) {
+		fprintf(stderr, "%s is not a valid IPv6 address\n", $2);
+		break;
+	}
+#else
+	fprintf(stderr, "Cannot find inet_pton(), IPv6 unsupported!");
+	break;
+#endif
+	conf.channel[conf.channel_num].u.udp.ipproto = AF_INET6;
+};
+
+udp_option : T_IPV4_DEST_ADDR T_IP
+{
+	__max_dedicated_links_reached();
+
+	if (!inet_aton($2, &conf.channel[conf.channel_num].u.udp.client)) {
+		fprintf(stderr, "%s is not a valid IPv4 address\n", $2);
+		break;
+	}
+	conf.channel[conf.channel_num].u.udp.ipproto = AF_INET;
+};
+
+udp_option : T_IPV6_DEST_ADDR T_IP
+{
+	__max_dedicated_links_reached();
+
+#ifdef HAVE_INET_PTON_IPV6
+	if (inet_pton(AF_INET6, $2,
+		      &conf.channel[conf.channel_num].u.udp.client) <= 0) {
+		fprintf(stderr, "%s is not a valid IPv6 address\n", $2);
+		break;
+	}
+#else
+	fprintf(stderr, "Cannot find inet_pton(), IPv6 unsupported!");
+	break;
+#endif
+	conf.channel[conf.channel_num].u.udp.ipproto = AF_INET6;
+};
+
+udp_option : T_IFACE T_STRING
+{
+	__max_dedicated_links_reached();
+	strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ);
+};
+
+udp_option : T_PORT T_NUMBER
+{
+	__max_dedicated_links_reached();
+	conf.channel[conf.channel_num].u.udp.port = $2;
+};
+
+udp_option: T_SNDBUFF T_NUMBER
+{
+	__max_dedicated_links_reached();
+	conf.channel[conf.channel_num].u.udp.sndbuf = $2;
+};
+
+udp_option: T_RCVBUFF T_NUMBER
+{
+	__max_dedicated_links_reached();
+	conf.channel[conf.channel_num].u.udp.rcvbuf = $2;
+};
+
+udp_option: T_CHECKSUM T_ON 
+{
+	__max_dedicated_links_reached();
+	conf.channel[conf.channel_num].u.udp.checksum = 0;
+};
+
+udp_option: T_CHECKSUM T_OFF
+{
+	__max_dedicated_links_reached();
+	conf.channel[conf.channel_num].u.udp.checksum = 1;
+};
+
 hashsize : T_HASHSIZE T_NUMBER
 {
 	conf.hashsize = $2;
@@ -493,6 +632,7 @@ sync_line: refreshtime
 	 | purge
 	 | checksum
 	 | multicast_line
+	 | udp_line
 	 | relax_transitions
 	 | delay_destroy_msgs
 	 | sync_mode_alarm
@@ -1133,7 +1273,7 @@ static void __kernel_filter_add_state(int value)
 			     &filter_proto);
 }
 
-static void __max_mcast_dedicated_links_reached(void)
+static void __max_dedicated_links_reached(void)
 {
 	if (conf.channel_num >= MULTICHANNEL_MAX) {
 		fprintf(stderr, "ERROR: too many dedicated links in "
diff --git a/src/udp.c b/src/udp.c
new file mode 100644
index 0000000..bad8db8
--- /dev/null
+++ b/src/udp.c
@@ -0,0 +1,261 @@
+/*
+ * (C) 2009 by Pablo Neira Ayuso <pablo at netfilter.org>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "udp.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <errno.h>
+#include <limits.h>
+
+struct udp_sock *udp_server_create(struct udp_conf *conf)
+{
+	int yes = 1;
+	struct udp_sock *m;
+	socklen_t socklen = sizeof(int);
+
+	m = calloc(sizeof(struct udp_sock), 1);
+	if (m == NULL)
+		return NULL;
+
+	switch(conf->ipproto) {
+	case AF_INET:
+	        m->addr.ipv4.sin_family = AF_INET;
+	        m->addr.ipv4.sin_port = htons(conf->port);
+	        m->addr.ipv4.sin_addr.s_addr = conf->server.inet_addr.s_addr;
+		m->sockaddr_len = sizeof(struct sockaddr_in); 
+		break;
+
+	case AF_INET6:
+		m->addr.ipv6.sin6_family = AF_INET6;
+		m->addr.ipv6.sin6_port = htons(conf->port);
+		m->addr.ipv6.sin6_addr = conf->server.inet_addr6;
+		m->sockaddr_len = sizeof(struct sockaddr_in6);
+		break;
+	}
+
+	m->fd = socket(conf->ipproto, SOCK_DGRAM, 0);
+	if (m->fd == -1) {
+		free(m);
+		return NULL;
+	}
+
+	if (setsockopt(m->fd, SOL_SOCKET, SO_REUSEADDR, &yes,
+				sizeof(int)) == -1) {
+		close(m->fd);
+		free(m);
+		return NULL;
+	}
+
+#ifndef SO_RCVBUFFORCE
+#define SO_RCVBUFFORCE 33
+#endif
+
+	if (conf->rcvbuf &&
+	    setsockopt(m->fd, SOL_SOCKET, SO_RCVBUFFORCE, &conf->rcvbuf,
+				sizeof(int)) == -1) {
+		/* not supported in linux kernel < 2.6.14 */
+		if (errno != ENOPROTOOPT) {
+			close(m->fd);
+			free(m);
+			return NULL;
+		}
+	}
+
+	getsockopt(m->fd, SOL_SOCKET, SO_RCVBUF, &conf->rcvbuf, &socklen);
+
+	if (bind(m->fd, (struct sockaddr *) &m->addr, m->sockaddr_len) == -1) {
+		close(m->fd);
+		free(m);
+		return NULL;
+	}
+
+	return m;
+}
+
+void udp_server_destroy(struct udp_sock *m)
+{
+	close(m->fd);
+	free(m);
+}
+
+struct udp_sock *udp_client_create(struct udp_conf *conf)
+{
+	int ret = 0;
+	struct udp_sock *m;
+	socklen_t socklen = sizeof(int);
+
+	m = calloc(sizeof(struct udp_sock), 1);
+	if (m == NULL)
+		return NULL;
+
+	m->fd = socket(conf->ipproto, SOCK_DGRAM, 0);
+	if (m->fd == -1) {
+		free(m);
+		return NULL;
+	}
+
+	if (setsockopt(m->fd, SOL_SOCKET, SO_NO_CHECK, &conf->checksum, 
+				sizeof(int)) == -1) {
+		close(m->fd);
+		free(m);
+		return NULL;
+	}
+
+#ifndef SO_SNDBUFFORCE
+#define SO_SNDBUFFORCE 32
+#endif
+
+	if (conf->sndbuf &&
+	    setsockopt(m->fd, SOL_SOCKET, SO_SNDBUFFORCE, &conf->sndbuf,
+				sizeof(int)) == -1) {
+		/* not supported in linux kernel < 2.6.14 */
+		if (errno != ENOPROTOOPT) {
+			close(m->fd);
+			free(m);
+			return NULL;
+		}
+	}
+
+	getsockopt(m->fd, SOL_SOCKET, SO_SNDBUF, &conf->sndbuf, &socklen);
+
+	switch(conf->ipproto) {
+	case AF_INET:
+		m->addr.ipv4.sin_family = AF_INET;
+		m->addr.ipv4.sin_port = htons(conf->port);
+		m->addr.ipv4.sin_addr = conf->client.inet_addr;
+		m->sockaddr_len = sizeof(struct sockaddr_in); 
+		break;
+	case AF_INET6:
+		m->addr.ipv6.sin6_family = AF_INET6;
+		m->addr.ipv6.sin6_port = htons(conf->port);
+		memcpy(&m->addr.ipv6.sin6_addr, &conf->client.inet_addr6,
+		       sizeof(struct in6_addr));
+		m->sockaddr_len = sizeof(struct sockaddr_in6); 
+		break;
+	default:
+		ret = -1;
+		break;
+	}
+
+	if (ret == -1) {
+		close(m->fd);
+		free(m);
+		m = NULL;
+	}
+
+	return m;
+}
+
+void udp_client_destroy(struct udp_sock *m)
+{
+	close(m->fd);
+	free(m);
+}
+
+ssize_t udp_send(struct udp_sock *m, const void *data, int size)
+{
+	ssize_t ret;
+	
+	ret = sendto(m->fd, 
+		     data,
+		     size,
+		     0,
+		     (struct sockaddr *) &m->addr,
+		     m->sockaddr_len);
+	if (ret == -1) {
+		m->stats.error++;
+		return ret;
+	}
+
+	m->stats.bytes += ret;
+	m->stats.messages++;  
+
+	return ret;
+}
+
+ssize_t udp_recv(struct udp_sock *m, void *data, int size)
+{
+	ssize_t ret;
+	socklen_t sin_size = sizeof(struct sockaddr_in);
+
+        ret = recvfrom(m->fd,
+		       data, 
+		       size,
+		       0,
+		       (struct sockaddr *)&m->addr,
+		       &sin_size);
+	if (ret == -1) {
+		m->stats.error++;
+		return ret;
+	}
+
+	m->stats.bytes += ret;
+	m->stats.messages++;
+
+	return ret;
+}
+
+int udp_get_fd(struct udp_sock *m)
+{
+	return m->fd;
+}
+
+int
+udp_snprintf_stats(char *buf, size_t buflen, char *ifname,
+		   struct udp_stats *s, struct udp_stats *r)
+{
+	size_t size;
+
+	size = snprintf(buf, buflen, "UDP traffic (active device=%s):\n"
+				     "%20llu Bytes sent "
+				     "%20llu Bytes recv\n"
+				     "%20llu Pckts sent "
+				     "%20llu Pckts recv\n"
+				     "%20llu Error send "
+				     "%20llu Error recv\n\n",
+				     ifname,
+				     (unsigned long long)s->bytes,
+				     (unsigned long long)r->bytes,
+				     (unsigned long long)s->messages,
+				     (unsigned long long)r->messages,
+				     (unsigned long long)s->error,
+				     (unsigned long long)r->error);
+	return size;
+}
+
+int
+udp_snprintf_stats2(char *buf, size_t buflen, const char *ifname, 
+		    const char *status, int active,
+		    struct udp_stats *s, struct udp_stats *r)
+{
+	size_t size;
+
+	size = snprintf(buf, buflen, 
+			"UDP traffic device=%s status=%s role=%s:\n"
+			"%20llu Bytes sent "
+			"%20llu Bytes recv\n"
+			"%20llu Pckts sent "
+			"%20llu Pckts recv\n"
+			"%20llu Error send "
+			"%20llu Error recv\n\n",
+			ifname, status, active ? "ACTIVE" : "BACKUP",
+			(unsigned long long)s->bytes,
+			(unsigned long long)r->bytes,
+			(unsigned long long)s->messages,
+			(unsigned long long)r->messages,
+			(unsigned long long)s->error,
+			(unsigned long long)r->error);
+	return size;
+}



More information about the netfilter-cvslog mailing list