diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/channel.c | 2 | ||||
-rw-r--r-- | src/channel_tipc.c | 144 | ||||
-rw-r--r-- | src/read_config_lex.l | 7 | ||||
-rw-r--r-- | src/read_config_yy.y | 107 | ||||
-rw-r--r-- | src/tipc.c | 252 |
6 files changed, 504 insertions, 10 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 7d7b2ac..995912f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,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_udp.c \ + channel.c multichannel.c channel_mcast.c channel_udp.c tipc.c channel_tipc.c \ tcp.c channel_tcp.c \ external_cache.c external_inject.c \ internal_cache.c internal_bypass.c \ diff --git a/src/channel.c b/src/channel.c index 818bb01..f362af7 100644 --- a/src/channel.c +++ b/src/channel.c @@ -24,6 +24,7 @@ static struct channel_ops *ops[CHANNEL_MAX]; extern struct channel_ops channel_mcast; extern struct channel_ops channel_udp; extern struct channel_ops channel_tcp; +extern struct channel_ops channel_tipc; static struct queue *errorq; @@ -32,6 +33,7 @@ int channel_init(void) ops[CHANNEL_MCAST] = &channel_mcast; ops[CHANNEL_UDP] = &channel_udp; ops[CHANNEL_TCP] = &channel_tcp; + ops[CHANNEL_TIPC] = &channel_tipc; errorq = queue_create("errorq", CONFIG(channelc).error_queue_length, 0); if (errorq == NULL) { diff --git a/src/channel_tipc.c b/src/channel_tipc.c new file mode 100644 index 0000000..71e3607 --- /dev/null +++ b/src/channel_tipc.c @@ -0,0 +1,144 @@ +/* + * (C) 2012 by Quentin Aebischer <quentin.aebicher@usherbrooke.ca> + * + * Derived work based on channel_mcast.c from: + * + * (C) 2006-2009 by Pablo Neira Ayuso <pablo@netfilter.org> + * (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 "tipc.h" + +static void +*channel_tipc_open(void *conf) +{ + struct tipc_channel *m; + struct tipc_conf *c = conf; + + m = calloc(sizeof(struct tipc_channel), 1); + if (m == NULL) + return NULL; + + m->client = tipc_client_create(c); + if (m->client == NULL) { + free(m); + return NULL; + } + + m->server = tipc_server_create(c); + if (m->server == NULL) { + tipc_client_destroy(m->client); + free(m); + return NULL; + } + return m; +} + +static int +channel_tipc_send(void *channel, const void *data, int len) +{ + struct tipc_channel *m = channel; + return tipc_send(m->client, data, len); +} + +static int +channel_tipc_recv(void *channel, char *buf, int size) +{ + struct tipc_channel *m = channel; + return tipc_recv(m->server, buf, size); +} + +static void +channel_tipc_close(void *channel) +{ + struct tipc_channel *m = channel; + tipc_client_destroy(m->client); + tipc_server_destroy(m->server); + free(m); +} + +static int +channel_tipc_get_fd(void *channel) +{ + struct tipc_channel *m = channel; + return tipc_get_fd(m->server); +} + +static void +channel_tipc_stats(struct channel *c, int fd) +{ + struct tipc_channel *m = c->data; + char ifname[IFNAMSIZ], buf[512]; + int size; + + if_indextoname(c->channel_ifindex, ifname); + size = tipc_snprintf_stats(buf, sizeof(buf), ifname, + &m->client->stats, &m->server->stats); + send(fd, buf, size, 0); +} + +static void +channel_tipc_stats_extended(struct channel *c, int active, + struct nlif_handle *h, int fd) +{ + struct tipc_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 = tipc_snprintf_stats2(buf, sizeof(buf), + ifname, status, active, + &m->client->stats, + &m->server->stats); + send(fd, buf, size, 0); +} + +static int +channel_tipc_isset(struct channel *c, fd_set *readfds) +{ + struct tipc_channel *m = c->data; + return tipc_isset(m->server, readfds); +} + +static int +channel_tipc_accept_isset(struct channel *c, fd_set *readfds) +{ + return 0; +} + +struct channel_ops channel_tipc = { + .headersiz = 60, /* IP header (20 bytes) + tipc unicast name message header 40 (bytes) (see http://tipc.sourceforge.net/doc/tipc_message_formats.html for details) */ + .open = channel_tipc_open, + .close = channel_tipc_close, + .send = channel_tipc_send, + .recv = channel_tipc_recv, + .get_fd = channel_tipc_get_fd, + .isset = channel_tipc_isset, + .accept_isset = channel_tipc_accept_isset, + .stats = channel_tipc_stats, + .stats_extended = channel_tipc_stats_extended, +}; diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 01fe4fc..ad37600 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -47,6 +47,7 @@ ip6_part {hex_255}":"? ip6_form1 {ip6_part}{0,16}"::"{ip6_part}{0,16} ip6_form2 ({hex_255}":"){16}{hex_255} ip6 {ip6_form1}{ip6_cidr}?|{ip6_form2}{ip6_cidr}? +tipc_name {integer}":"{integer} string [a-zA-Z][a-zA-Z0-9\.\-]* persistent [P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T] nack [N|n][A|a][C|c][K|k] @@ -63,9 +64,13 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "IPv4_interface" { return T_IPV4_IFACE; } "IPv6_interface" { return T_IPV6_IFACE; } "Interface" { return T_IFACE; } +"TIPC_Destination_Name" { return T_TIPC_DEST_NAME; } +"TIPC_Name" { return T_TIPC_NAME; } +"TIPC_Message_Importance" { return T_TIPC_MESSAGE_IMPORTANCE; } "Multicast" { return T_MULTICAST; } "UDP" { return T_UDP; } "TCP" { return T_TCP; } +"TIPC" { return T_TIPC; } "HashSize" { return T_HASHSIZE; } "RefreshTime" { return T_REFRESH; } "CacheTimeout" { return T_EXPIRE; } @@ -149,6 +154,8 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] {signed_integer} { yylval.val = atoi(yytext); return T_SIGNED_NUMBER; } {ip4} { yylval.string = strdup(yytext); return T_IP; } {ip6} { yylval.string = strdup(yytext); return T_IP; } +{tipc_name} { yylval.string = strdup(yytext); return T_TIPC_NAME_VAL; } + {path} { yylval.string = strdup(yytext); return T_PATH_VAL; } {alarm} { return T_ALARM; } {persistent} { fprintf(stderr, "\nWARNING: Now `persistent' mode " diff --git a/src/read_config_yy.y b/src/read_config_yy.y index b22784c..21d1c20 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -30,6 +30,7 @@ #include "cidr.h" #include <syslog.h> #include <sched.h> +#include <linux/tipc.h> #include <libnetfilter_conntrack/libnetfilter_conntrack.h> #include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h> @@ -74,8 +75,9 @@ static void __max_dedicated_links_reached(void); %token T_SCHEDULER T_TYPE T_PRIO T_NETLINK_EVENTS_RELIABLE %token T_DISABLE_INTERNAL_CACHE T_DISABLE_EXTERNAL_CACHE T_ERROR_QUEUE_LENGTH %token T_OPTIONS T_TCP_WINDOW_TRACKING T_EXPECT_SYNC +%token T_TIPC T_TIPC_DEST_NAME T_TIPC_NAME T_TIPC_MESSAGE_IMPORTANCE -%token <string> T_IP T_PATH_VAL +%token <string> T_IP T_PATH_VAL T_TIPC_NAME_VAL %token <val> T_NUMBER %token <val> T_SIGNED_NUMBER %token <string> T_STRING @@ -150,7 +152,7 @@ syslog_facility : T_SYSLOG T_STRING if (conf.stats.syslog_facility != -1 && conf.syslog_facility != conf.stats.syslog_facility) - print_err(CTD_CFG_WARN, "conflicting Syslog facility " + print_err(CTD_CFG_WARN, "conflicting Syslog facility " "values, defaulting to General"); }; @@ -309,7 +311,7 @@ multicast_option : T_IPV4_ADDR T_IP break; } - if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) { + if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) { print_err(CTD_CFG_WARN, "your multicast address is IPv4 but " "is binded to an IPv6 interface? " "Surely, this is not what you want"); @@ -368,7 +370,7 @@ multicast_option : T_IPV4_IFACE T_IP break; } - if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) { + if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) { print_err(CTD_CFG_WARN, "your multicast interface is IPv4 but " "is binded to an IPv6 interface? " "Surely, this is not what you want"); @@ -381,7 +383,7 @@ multicast_option : T_IPV4_IFACE T_IP multicast_option : T_IPV6_IFACE T_IP { print_err(CTD_CFG_WARN, "`IPv6_interface' not required, ignoring"); -} +}; multicast_option : T_IFACE T_STRING { @@ -440,6 +442,92 @@ multicast_option: T_CHECKSUM T_OFF conf.channel[conf.channel_num].u.mcast.checksum = 1; }; +tipc_line : T_TIPC '{' tipc_options '}' +{ + if (conf.channel_type_global != CHANNEL_NONE && + conf.channel_type_global != CHANNEL_TIPC) { + print_err(CTD_CFG_ERROR, "cannot use `TIPC' with other " + "dedicated link protocols!"); + exit(EXIT_FAILURE); + } + conf.channel_type_global = CHANNEL_TIPC; + conf.channel[conf.channel_num].channel_type = CHANNEL_TIPC; + conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED; + conf.channel_num++; +}; + +tipc_line : T_TIPC T_DEFAULT '{' tipc_options '}' +{ + if (conf.channel_type_global != CHANNEL_NONE && + conf.channel_type_global != CHANNEL_TIPC) { + print_err(CTD_CFG_ERROR, "cannot use `TIPC' with other " + "dedicated link protocols!"); + exit(EXIT_FAILURE); + } + conf.channel_type_global = CHANNEL_TIPC; + conf.channel[conf.channel_num].channel_type = CHANNEL_TIPC; + conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT | + CHANNEL_F_BUFFERED; + conf.channel_default = conf.channel_num; + conf.channel_num++; +}; + +tipc_options : + | tipc_options tipc_option; + +tipc_option : T_TIPC_DEST_NAME T_TIPC_NAME_VAL +{ + __max_dedicated_links_reached(); + + if(sscanf($2, "%d:%d", &conf.channel[conf.channel_num].u.tipc.client.type, &conf.channel[conf.channel_num].u.tipc.client.instance) != 2) { + print_err(CTD_CFG_WARN, "Please enter TIPC name in the form type:instance (ex: 1000:50)"); + break; + } + conf.channel[conf.channel_num].u.tipc.ipproto = AF_TIPC; +}; + +tipc_option : T_TIPC_NAME T_TIPC_NAME_VAL +{ + __max_dedicated_links_reached(); + + if(sscanf($2, "%d:%d", &conf.channel[conf.channel_num].u.tipc.server.type, &conf.channel[conf.channel_num].u.tipc.server.instance) != 2) { + print_err(CTD_CFG_WARN, "Please enter TIPC name in the form type:instance (ex: 1000:50)"); + break; + } + conf.channel[conf.channel_num].u.tipc.ipproto = AF_TIPC; +}; + +tipc_option : T_IFACE T_STRING +{ + unsigned int idx; + + __max_dedicated_links_reached(); + + strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ); + + idx = if_nametoindex($2); + if (!idx) { + print_err(CTD_CFG_WARN, "%s is an invalid interface", $2); + break; + } +}; + +tipc_option : T_TIPC_MESSAGE_IMPORTANCE T_STRING +{ + if(!strcmp("LOW", $2)) + conf.channel[conf.channel_num].u.tipc.msgImportance = TIPC_LOW_IMPORTANCE; + if(!strcmp("MEDIUM", $2)) + conf.channel[conf.channel_num].u.tipc.msgImportance = TIPC_MEDIUM_IMPORTANCE; + if(!strcmp("HIGH", $2)) + conf.channel[conf.channel_num].u.tipc.msgImportance = TIPC_HIGH_IMPORTANCE; + if(!strcmp("CRITICAL", $2)) + conf.channel[conf.channel_num].u.tipc.msgImportance = TIPC_CRITICAL_IMPORTANCE; + if(conf.channel[conf.channel_num].u.tipc.msgImportance < TIPC_LOW_IMPORTANCE || conf.channel[conf.channel_num].u.tipc.msgImportance > TIPC_CRITICAL_IMPORTANCE) { + print_err(CTD_CFG_WARN, "%s is an invalid message importance level (defaulting to TIPC_HIGH_IMPORTANCE)", $2); + conf.channel[conf.channel_num].u.tipc.msgImportance = TIPC_HIGH_IMPORTANCE; + } +}; + udp_line : T_UDP '{' udp_options '}' { if (conf.channel_type_global != CHANNEL_NONE && @@ -800,6 +888,7 @@ sync_line: refreshtime | multicast_line | udp_line | tcp_line + | tipc_line | relax_transitions | delay_destroy_msgs | sync_mode_alarm @@ -861,7 +950,7 @@ option: T_EXPECT_SYNC '{' expect_list '}' }; expect_list: - | expect_list expect_item ; + | expect_list expect_item ; expect_item: T_STRING { @@ -887,8 +976,8 @@ sync_mode_alarm_list: | sync_mode_alarm_list sync_mode_alarm_line; sync_mode_alarm_line: refreshtime - | expiretime - | timeout + | expiretime + | timeout | purge | relax_transitions | delay_destroy_msgs @@ -1020,7 +1109,7 @@ tcp_state: T_ESTABLISHED TCP_CONNTRACK_ESTABLISHED); __kernel_filter_add_state(TCP_CONNTRACK_ESTABLISHED); -}; +} tcp_state: T_FIN_WAIT { ct_filter_add_state(STATE(us_filter), diff --git a/src/tipc.c b/src/tipc.c new file mode 100644 index 0000000..37f6128 --- /dev/null +++ b/src/tipc.c @@ -0,0 +1,252 @@ +/* + * + * (C) 2012 by Quentin Aebischer <quentin.aebicher@usherbrooke.ca> + * + * Derived work based on mcast.c from: + * + * (C) 2006-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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Description: tipc socket library + */ + + +#include "tipc.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> +#include <libnfnetlink/libnfnetlink.h> + +#ifdef CTD_TIPC_DEBUG +#include <fcntl.h> /* used for debug purposes */ +#endif + +struct tipc_sock *tipc_server_create(struct tipc_conf *conf) +{ + struct tipc_sock *m; + +#ifdef CTD_TIPC_DEBUG + int val = 0; +#endif + + m = (struct tipc_sock *) malloc(sizeof(struct tipc_sock)); + if (!m) + return NULL; + memset(m, 0, sizeof(struct tipc_sock)); + m->sockaddr_len = sizeof(struct sockaddr_tipc); + + m->addr.family = AF_TIPC; + m->addr.addrtype = TIPC_ADDR_NAME; + m->addr.scope = TIPC_CLUSTER_SCOPE; + m->addr.addr.name.name.type = conf->server.type; + m->addr.addr.name.name.instance = conf->server.instance; + + if ((m->fd = socket(AF_TIPC, SOCK_RDM, 0)) == -1) { + free(m); + return NULL; + } + +#ifdef CTD_TIPC_DEBUG + setsockopt(m->fd, SOL_TIPC, TIPC_DEST_DROPPABLE, &val, sizeof(val)); /*used for debug purposes */ +#endif + if (bind(m->fd, (struct sockaddr *) &m->addr, m->sockaddr_len) == -1) { + close(m->fd); + free(m); + return NULL; + } + + return m; +} + +void tipc_server_destroy(struct tipc_sock *m) +{ + close(m->fd); + free(m); +} + +struct tipc_sock *tipc_client_create(struct tipc_conf *conf) +{ + struct tipc_sock *m; + + m = (struct tipc_sock *) malloc(sizeof(struct tipc_sock)); + if (!m) + return NULL; + memset(m, 0, sizeof(struct tipc_sock)); + + m->addr.family = AF_TIPC; + m->addr.addrtype = TIPC_ADDR_NAME; + m->addr.addr.name.name.type = conf->client.type; + m->addr.addr.name.name.instance = conf->client.instance; + m->addr.addr.name.domain = 0; + m->sockaddr_len = sizeof(struct sockaddr_tipc); + + if ((m->fd = socket(AF_TIPC, SOCK_RDM, 0)) == -1) { + free(m); + return NULL; + } + +#ifdef CTD_TIPC_DEBUG + setsockopt(m->fd, SOL_TIPC, TIPC_DEST_DROPPABLE, &val, sizeof(val)); + fcntl(m->fd, F_SETFL, O_NONBLOCK); +#endif + setsockopt(m->fd, SOL_TIPC, TIPC_IMPORTANCE, &conf->msgImportance, sizeof(conf->msgImportance)); + + return m; +} + +void tipc_client_destroy(struct tipc_sock *m) +{ + close(m->fd); + free(m); +} + +ssize_t tipc_send(struct tipc_sock *m, const void *data, int size) +{ + ssize_t ret; +#ifdef CTD_TIPC_DEBUG + char buf[50]; +#endif + + ret = sendto(m->fd, + data, + size, + 0, + (struct sockaddr *) &m->addr, + m->sockaddr_len); + if (ret == -1) { + m->stats.error++; + return ret; + } + +#ifdef CTD_TIPC_DEBUG + if(!recv(m->fd,buf,sizeof(buf),0)) + m->stats.returned_messages++; +#endif + + m->stats.bytes += ret; + m->stats.messages++; + + return ret; +} + +ssize_t tipc_recv(struct tipc_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) { + if (errno != EAGAIN) + m->stats.error++; + return ret; + } + +#ifdef CTD_TIPC_DEBUG + if (!ret) + m->stats.returned_messages++; +#endif + + m->stats.bytes += ret; + m->stats.messages++; + + return ret; +} + +int tipc_get_fd(struct tipc_sock *m) +{ + return m->fd; +} + +int tipc_isset(struct tipc_sock *m, fd_set *readfds) +{ + return FD_ISSET(m->fd, readfds); +} + +int +tipc_snprintf_stats(char *buf, size_t buflen, char *ifname, + struct tipc_stats *s, struct tipc_stats *r) +{ + size_t size; + + size = snprintf(buf, buflen, "tipc 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", +#ifdef CTD_TIPC_DEBUG + "%20llu Returned messages\n\n", +#endif + 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) +#ifdef CTD_TIPC_DEBUG + (unsigned long long)s->returned_messages); +#else + ; +#endif + return size; +} + +int +tipc_snprintf_stats2(char *buf, size_t buflen, const char *ifname, + const char *status, int active, + struct tipc_stats *s, struct tipc_stats *r) +{ + size_t size; + + size = snprintf(buf, buflen, + "tipc 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", +#ifdef CTD_TIPC_DEBUG + "%20llu Returned messages\n\n", +#endif + 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); +#ifdef CTD_TIPC_DEBUG + (unsigned long long)s->returned_messages); +#else + ; +#endif + return size; +} |