diff options
-rw-r--r-- | doc/sync/alarm/conntrackd.conf | 52 | ||||
-rw-r--r-- | doc/sync/ftfw/conntrackd.conf | 52 | ||||
-rw-r--r-- | doc/sync/notrack/conntrackd.conf | 52 | ||||
-rw-r--r-- | include/Makefile.am | 2 | ||||
-rw-r--r-- | include/channel.h | 9 | ||||
-rw-r--r-- | include/conntrackd.h | 1 | ||||
-rw-r--r-- | include/udp.h | 58 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/channel.c | 2 | ||||
-rw-r--r-- | src/channel_udp.c | 123 | ||||
-rw-r--r-- | src/read_config_lex.l | 10 | ||||
-rw-r--r-- | src/read_config_yy.y | 170 | ||||
-rw-r--r-- | src/udp.c | 261 |
13 files changed, 764 insertions, 32 deletions
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@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@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; +} |