From 4f92d3200407e6db1401cadb0e68d0f2ab96554f Mon Sep 17 00:00:00 2001 From: David du Colombier Date: Thu, 24 Mar 2011 11:09:31 +0100 Subject: [PATCH] [MEDIUM] IPv6 support for stick-tables Since IPv6 is a different type than IPv4, the pattern fetch functions src6 and dst6 were added. IPv6 stick-tables can also fetch IPv4 addresses with src and dst. In this case, the IPv4 addresses are mapped to their IPv6 counterpart, according to RFC 4291. --- include/common/standard.h | 14 ++++++++ include/proto/proto_tcp.h | 15 +++++---- include/types/pattern.h | 4 +++ include/types/stick_table.h | 4 ++- src/dumpstats.c | 9 +++++- src/pattern.c | 46 ++++++++++++++++++++++---- src/proto_tcp.c | 47 ++++++++++++++++++++++----- src/session.c | 64 ++++++++++++++++++------------------- src/standard.c | 48 ++++++++++++++++++++++++++++ src/stick_table.c | 59 +++++++++++++++++++++++++++++----- 10 files changed, 246 insertions(+), 64 deletions(-) diff --git a/include/common/standard.h b/include/common/standard.h index e20eb77545..e7a1052841 100644 --- a/include/common/standard.h +++ b/include/common/standard.h @@ -549,4 +549,18 @@ static inline int set_host_port(struct sockaddr_storage *addr, int port) return 0; } +/* Return true if IPv4 address is part of the network */ +extern int in_net_ipv4(struct in_addr *addr, struct in_addr *mask, struct in_addr *net); + +/* Return true if IPv6 address is part of the network */ +extern int in_net_ipv6(struct in6_addr *addr, struct in6_addr *mask, struct in6_addr *net); + +/* Map IPv4 adress on IPv6 address, as specified in RFC 3513. */ +extern void v4tov6(struct in6_addr *sin6_addr, struct in_addr *sin_addr); + +/* Map IPv6 adress on IPv4 address, as specified in RFC 3513. + * Return true if conversion is possible and false otherwise. + */ +extern int v6tov4(struct in_addr *sin_addr, struct in6_addr *sin6_addr); + #endif /* _COMMON_STANDARD_H */ diff --git a/include/proto/proto_tcp.h b/include/proto/proto_tcp.h index 26e06df8cc..c7aef6a89c 100644 --- a/include/proto/proto_tcp.h +++ b/include/proto/proto_tcp.h @@ -36,18 +36,19 @@ int tcp_inspect_response(struct session *s, struct buffer *rep, int an_bit); int tcp_persist_rdp_cookie(struct session *s, struct buffer *req, int an_bit); int tcp_exec_req_rules(struct session *s); -/* Converts the TCPv4 source address to a stick_table key usable for table +/* Converts the TCP source address to a stick_table key usable for table * lookups. Returns either NULL if the source cannot be converted (eg: not * IPv4) or a pointer to the converted result in static_table_key in the * appropriate format (IP). */ -static inline struct stktable_key *tcpv4_src_to_stktable_key(struct session *s) +static inline struct stktable_key *tcp_src_to_stktable_key(struct session *s) { - /* right now we only support IPv4 */ - if (s->si[0].addr.c.from.ss_family != AF_INET) - return NULL; - - static_table_key.key = (void *)&((struct sockaddr_in *)&s->si[0].addr.c.from)->sin_addr; + switch (s->si[0].addr.c.from.ss_family) { + case AF_INET: + static_table_key.key = (void *)&((struct sockaddr_in *)&s->si[0].addr.c.from)->sin_addr; + case AF_INET6: + static_table_key.key = (void *)&((struct sockaddr_in6 *)&s->si[0].addr.c.from)->sin6_addr; + } return &static_table_key; } diff --git a/include/types/pattern.h b/include/types/pattern.h index a3d5c3673b..9b4e3405d9 100644 --- a/include/types/pattern.h +++ b/include/types/pattern.h @@ -29,6 +29,7 @@ /* pattern in and out types */ enum { PATTERN_TYPE_IP = 0, /* ipv4 type */ + PATTERN_TYPE_IPV6, /* ipv6 type */ PATTERN_TYPE_INTEGER, /* unsigned 32bits integer type */ PATTERN_TYPE_STRING, /* char string type */ PATTERN_TYPE_DATA, /* buffer type */ @@ -41,6 +42,7 @@ enum { /* pattern arg types */ enum { PATTERN_ARG_TYPE_IP = 0, /* ipv4 type */ + PATTERN_ARG_TYPE_IPV6, /* ipv6 type */ PATTERN_ARG_TYPE_INTEGER, /* unsigned 32bits integer type */ PATTERN_ARG_TYPE_SINTEGER, /* signed 32bits integer type */ PATTERN_ARG_TYPE_STRING /* string type */ @@ -53,6 +55,7 @@ enum { union pattern_arg_data { struct in_addr ip; /* used for ipv4 type */ + struct in6_addr ipv6; /* used for ipv6 type */ uint32_t integer; /* used for unsigned 32bits integer type */ int sinteger; /* used for signed 32bits integer type */ struct chunk str; @@ -66,6 +69,7 @@ struct pattern_arg { /* pattern result data */ union pattern_data { struct in_addr ip; /* used for ipv4 type */ + struct in6_addr ipv6; /* used for ipv6 type */ uint32_t integer; /* used for unsigned 32bits integer type */ struct chunk str; /* used for char string type or buffers*/ }; diff --git a/include/types/stick_table.h b/include/types/stick_table.h index e519f490e3..cccf9fbecd 100644 --- a/include/types/stick_table.h +++ b/include/types/stick_table.h @@ -35,6 +35,7 @@ /* stick table key types */ enum { STKTABLE_TYPE_IP = 0, /* table key is ipv4 */ + STKTABLE_TYPE_IPV6, /* table key is ipv6 */ STKTABLE_TYPE_INTEGER, /* table key is unsigned 32bit integer */ STKTABLE_TYPE_STRING, /* table key is a null terminated string */ STKTABLE_TYPE_BINARY, /* table key is a buffer of data */ @@ -172,7 +173,8 @@ extern struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES]; /* stick table key data */ union stktable_key_data { - struct in_addr ip; /* used to store an ip key */ + struct in_addr ip; /* used to store an ipv4 key */ + struct in6_addr ipv6; /* used to store an ipv6 key */ uint32_t integer; /* used to store an integer key */ char buf[BUFSIZE]; /* used to store a null terminated string key or a buffer of data */ }; diff --git a/src/dumpstats.c b/src/dumpstats.c index 8b8c3fc320..75baadb06d 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -3312,12 +3312,19 @@ int stats_dump_table_to_buffer(struct stream_interface *si) chunk_printf(&msg, "%p:", si->applet.ctx.table.entry); if (si->applet.ctx.table.proxy->table.type == STKTABLE_TYPE_IP) { - char addr[16]; + char addr[INET_ADDRSTRLEN]; inet_ntop(AF_INET, (const void *)&si->applet.ctx.table.entry->key.key, addr, sizeof(addr)); chunk_printf(&msg, " key=%s", addr); } + else if (si->applet.ctx.table.proxy->table.type == STKTABLE_TYPE_IPV6) { + char addr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, + (const void *)&si->applet.ctx.table.entry->key.key, + addr, sizeof(addr)); + chunk_printf(&msg, " key=%s", addr); + } else if (si->applet.ctx.table.proxy->table.type == STKTABLE_TYPE_INTEGER) { chunk_printf(&msg, " key=%u", *(unsigned int *)si->applet.ctx.table.entry->key.key); } diff --git a/src/pattern.c b/src/pattern.c index ba8d5a01e9..e705f00c31 100644 --- a/src/pattern.c +++ b/src/pattern.c @@ -146,6 +146,32 @@ static int c_ip2str(union pattern_data *data) return 1; } +static int c_ip2ipv6(union pattern_data *data) +{ + v4tov6(&data->ipv6, &data->ip); + return 1; +} + +static int c_ipv62str(union pattern_data *data) +{ + struct chunk *trash = get_trash_chunk(); + + if (!inet_ntop(AF_INET6, (void *)&data->ipv6, trash->str, trash->size)) + return 0; + + trash->len = strlen(trash->str); + pattern_data_setstring(data, trash); + + return 1; +} + +/* +static int c_ipv62ip(union pattern_data *data) +{ + return v6tov4(&data->ip, &data->ipv6); +} +*/ + static int c_int2ip(union pattern_data *data) { data->ip.s_addr = htonl(data->integer); @@ -159,6 +185,11 @@ static int c_str2ip(union pattern_data *data) return 1; } +static int c_str2ipv6(union pattern_data *data) +{ + return inet_pton(AF_INET6, data->str.str, &data->ipv6); +} + static int c_int2str(union pattern_data *data) { struct chunk *trash = get_trash_chunk(); @@ -222,13 +253,14 @@ static int c_str2int(union pattern_data *data) typedef int (*pattern_cast_fct)(union pattern_data *data); static pattern_cast_fct pattern_casts[PATTERN_TYPES][PATTERN_TYPES] = { -/* to: IP INTEGER STRING DATA CONSTSTRING CONSTDATA */ -/* from: IP */ { c_donothing, c_ip2int, c_ip2str, NULL, c_ip2str, NULL }, -/* INTEGER */ { c_int2ip, c_donothing, c_int2str, NULL, c_int2str, NULL }, -/* STRING */ { c_str2ip, c_str2int, c_donothing, c_donothing, c_donothing, c_donothing }, -/* DATA */ { NULL, NULL, NULL, c_donothing, NULL, c_donothing }, -/* CONSTSTRING */ { c_str2ip, c_str2int, c_datadup, c_datadup, c_donothing, c_donothing }, -/* CONSTDATA */ { NULL, NULL, NULL, c_datadup, NULL, NULL }, +/* to: IP IPV6 INTEGER STRING DATA CONSTSTRING CONSTDATA */ +/* from: IP */ { c_donothing, c_ip2ipv6, c_ip2int, c_ip2str, NULL, c_ip2str, NULL }, +/* IPV6 */ { NULL, c_donothing, NULL, c_ipv62str, NULL, c_ipv62str, NULL }, +/* INTEGER */ { c_int2ip, NULL, c_donothing, c_int2str, NULL, c_int2str, NULL }, +/* STRING */ { c_str2ip, c_str2ipv6, c_str2int, c_donothing, c_donothing, c_donothing, c_donothing }, +/* DATA */ { NULL, NULL, NULL, NULL, c_donothing, NULL, c_donothing }, +/* CONSTSTRING */ { c_str2ip, c_str2ipv6, c_str2int, c_datadup, c_datadup, c_donothing, c_donothing }, +/* CONSTDATA */ { NULL, NULL, NULL, NULL, c_datadup, NULL, c_donothing }, }; diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 3c8a04f717..ca993a6fc3 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -745,7 +745,7 @@ int tcp_inspect_request(struct session *s, struct buffer *req, int an_bit) * to consider rule->act_prm->trk_ctr.type. */ t = rule->act_prm.trk_ctr.table.t; - ts = stktable_get_entry(t, tcpv4_src_to_stktable_key(s)); + ts = stktable_get_entry(t, tcp_src_to_stktable_key(s)); if (ts) { session_track_stkctr1(s, t, ts); if (s->fe != s->be) @@ -761,7 +761,7 @@ int tcp_inspect_request(struct session *s, struct buffer *req, int an_bit) * to consider rule->act_prm->trk_ctr.type. */ t = rule->act_prm.trk_ctr.table.t; - ts = stktable_get_entry(t, tcpv4_src_to_stktable_key(s)); + ts = stktable_get_entry(t, tcp_src_to_stktable_key(s)); if (ts) { session_track_stkctr2(s, t, ts); if (s->fe != s->be) @@ -915,7 +915,7 @@ int tcp_exec_req_rules(struct session *s) * to consider rule->act_prm->trk_ctr.type. */ t = rule->act_prm.trk_ctr.table.t; - ts = stktable_get_entry(t, tcpv4_src_to_stktable_key(s)); + ts = stktable_get_entry(t, tcp_src_to_stktable_key(s)); if (ts) session_track_stkctr1(s, t, ts); } @@ -928,7 +928,7 @@ int tcp_exec_req_rules(struct session *s) * to consider rule->act_prm->trk_ctr.type. */ t = rule->act_prm.trk_ctr.table.t; - ts = stktable_get_entry(t, tcpv4_src_to_stktable_key(s)); + ts = stktable_get_entry(t, tcp_src_to_stktable_key(s)); if (ts) session_track_stkctr2(s, t, ts); } @@ -1275,7 +1275,7 @@ acl_fetch_src(struct proxy *px, struct session *l4, void *l7, int dir, return 1; } -/* extract the connection's source address */ +/* extract the connection's source ipv4 address */ static int pattern_fetch_src(struct proxy *px, struct session *l4, void *l7, int dir, const struct pattern_arg *arg_p, int arg_i, union pattern_data *data) @@ -1287,6 +1287,17 @@ pattern_fetch_src(struct proxy *px, struct session *l4, void *l7, int dir, return 1; } +/* extract the connection's source ipv6 address */ +static int +pattern_fetch_src6(struct proxy *px, struct session *l4, void *l7, int dir, + const struct pattern_arg *arg_p, int arg_i, union pattern_data *data) +{ + if (l4->si[0].addr.c.from.ss_family != AF_INET6) + return 0; + + memcpy(data->ipv6.s6_addr, ((struct sockaddr_in6 *)&l4->si[0].addr.c.from)->sin6_addr.s6_addr, sizeof(data->ipv6.s6_addr)); + return 1; +} /* set test->i to the connection's source port */ static int @@ -1326,7 +1337,7 @@ acl_fetch_dst(struct proxy *px, struct session *l4, void *l7, int dir, } -/* extract the connection's destination address */ +/* extract the connection's destination ipv4 address */ static int pattern_fetch_dst(struct proxy *px, struct session *l4, void *l7, int dir, const struct pattern_arg *arg_p, int arg_i, union pattern_data *data) @@ -1341,6 +1352,21 @@ pattern_fetch_dst(struct proxy *px, struct session *l4, void *l7, int dir, return 1; } +/* extract the connection's destination ipv6 address */ +static int +pattern_fetch_dst6(struct proxy *px, struct session *l4, void *l7, int dir, + const struct pattern_arg *arg_p, int arg_i, union pattern_data *data) +{ + if (!(l4->flags & SN_FRT_ADDR_SET)) + get_frt_addr(l4); + + if (l4->si[0].addr.c.to.ss_family != AF_INET6) + return 0; + + memcpy(data->ipv6.s6_addr, ((struct sockaddr_in6 *)&l4->si[0].addr.c.to)->sin6_addr.s6_addr, sizeof(data->ipv6.s6_addr)); + return 1; +} + /* set test->i to the frontend connexion's destination port */ static int acl_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir, @@ -1367,10 +1393,13 @@ pattern_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir, if (!(l4->flags & SN_FRT_ADDR_SET)) get_frt_addr(l4); - if (l4->si[0].addr.c.to.ss_family != AF_INET) + if (l4->si[0].addr.c.to.ss_family == AF_INET) + data->integer = ntohs(((struct sockaddr_in *)&l4->si[0].addr.c.to)->sin_port); + else if (l4->si[0].addr.c.to.ss_family == AF_INET6) + data->integer = ntohs(((struct sockaddr_in6 *)&l4->si[0].addr.c.to)->sin6_port); + else return 0; - data->integer = ntohs(((struct sockaddr_in *)&l4->si[0].addr.c.to)->sin_port); return 1; } @@ -1566,7 +1595,9 @@ static struct acl_kw_list acl_kws = {{ },{ /* Note: must not be declared as its list will be overwritten */ static struct pattern_fetch_kw_list pattern_fetch_keywords = {{ },{ { "src", pattern_fetch_src, NULL, PATTERN_TYPE_IP, PATTERN_FETCH_REQ }, + { "src6", pattern_fetch_src6, NULL, PATTERN_TYPE_IPV6, PATTERN_FETCH_REQ }, { "dst", pattern_fetch_dst, NULL, PATTERN_TYPE_IP, PATTERN_FETCH_REQ }, + { "dst6", pattern_fetch_dst6, NULL, PATTERN_TYPE_IPV6, PATTERN_FETCH_REQ }, { "dst_port", pattern_fetch_dport, NULL, PATTERN_TYPE_INTEGER, PATTERN_FETCH_REQ }, { "payload", pattern_fetch_payload, pattern_arg_fetch_payload, PATTERN_TYPE_CONSTDATA, PATTERN_FETCH_REQ|PATTERN_FETCH_RTR }, { "payload_lv", pattern_fetch_payloadlv, pattern_arg_fetch_payloadlv, PATTERN_TYPE_CONSTDATA, PATTERN_FETCH_REQ|PATTERN_FETCH_RTR }, diff --git a/src/session.c b/src/session.c index b7914d030b..27f4fbd1c6 100644 --- a/src/session.c +++ b/src/session.c @@ -2244,9 +2244,9 @@ acl_fetch_src_get_gpc0(struct proxy *px, struct session *l4, void *l7, int dir, { struct stktable_key *key; - key = tcpv4_src_to_stktable_key(l4); + key = tcp_src_to_stktable_key(l4); if (!key) - return 0; /* only TCPv4 is supported right now */ + return 0; if (expr->arg_len) px = find_stktable(expr->arg.str); @@ -2307,9 +2307,9 @@ acl_fetch_src_inc_gpc0(struct proxy *px, struct session *l4, void *l7, int dir, { struct stktable_key *key; - key = tcpv4_src_to_stktable_key(l4); + key = tcp_src_to_stktable_key(l4); if (!key) - return 0; /* only TCPv4 is supported right now */ + return 0; if (expr->arg_len) px = find_stktable(expr->arg.str); @@ -2366,9 +2366,9 @@ acl_fetch_src_conn_cnt(struct proxy *px, struct session *l4, void *l7, int dir, { struct stktable_key *key; - key = tcpv4_src_to_stktable_key(l4); + key = tcp_src_to_stktable_key(l4); if (!key) - return 0; /* only TCPv4 is supported right now */ + return 0; if (expr->arg_len) px = find_stktable(expr->arg.str); @@ -2430,9 +2430,9 @@ acl_fetch_src_conn_rate(struct proxy *px, struct session *l4, void *l7, int dir, { struct stktable_key *key; - key = tcpv4_src_to_stktable_key(l4); + key = tcp_src_to_stktable_key(l4); if (!key) - return 0; /* only TCPv4 is supported right now */ + return 0; if (expr->arg_len) px = find_stktable(expr->arg.str); @@ -2454,9 +2454,9 @@ acl_fetch_src_updt_conn_cnt(struct proxy *px, struct session *l4, void *l7, int struct stktable_key *key; void *ptr; - key = tcpv4_src_to_stktable_key(l4); + key = tcp_src_to_stktable_key(l4); if (!key) - return 0; /* only TCPv4 is supported right now */ + return 0; if (expr->arg_len) px = find_stktable(expr->arg.str); @@ -2524,9 +2524,9 @@ acl_fetch_src_conn_cur(struct proxy *px, struct session *l4, void *l7, int dir, { struct stktable_key *key; - key = tcpv4_src_to_stktable_key(l4); + key = tcp_src_to_stktable_key(l4); if (!key) - return 0; /* only TCPv4 is supported right now */ + return 0; if (expr->arg_len) px = find_stktable(expr->arg.str); @@ -2583,9 +2583,9 @@ acl_fetch_src_sess_cnt(struct proxy *px, struct session *l4, void *l7, int dir, { struct stktable_key *key; - key = tcpv4_src_to_stktable_key(l4); + key = tcp_src_to_stktable_key(l4); if (!key) - return 0; /* only TCPv4 is supported right now */ + return 0; if (expr->arg_len) px = find_stktable(expr->arg.str); @@ -2647,9 +2647,9 @@ acl_fetch_src_sess_rate(struct proxy *px, struct session *l4, void *l7, int dir, { struct stktable_key *key; - key = tcpv4_src_to_stktable_key(l4); + key = tcp_src_to_stktable_key(l4); if (!key) - return 0; /* only TCPv4 is supported right now */ + return 0; if (expr->arg_len) px = find_stktable(expr->arg.str); @@ -2706,9 +2706,9 @@ acl_fetch_src_http_req_cnt(struct proxy *px, struct session *l4, void *l7, int d { struct stktable_key *key; - key = tcpv4_src_to_stktable_key(l4); + key = tcp_src_to_stktable_key(l4); if (!key) - return 0; /* only TCPv4 is supported right now */ + return 0; if (expr->arg_len) px = find_stktable(expr->arg.str); @@ -2770,9 +2770,9 @@ acl_fetch_src_http_req_rate(struct proxy *px, struct session *l4, void *l7, int { struct stktable_key *key; - key = tcpv4_src_to_stktable_key(l4); + key = tcp_src_to_stktable_key(l4); if (!key) - return 0; /* only TCPv4 is supported right now */ + return 0; if (expr->arg_len) px = find_stktable(expr->arg.str); @@ -2829,9 +2829,9 @@ acl_fetch_src_http_err_cnt(struct proxy *px, struct session *l4, void *l7, int d { struct stktable_key *key; - key = tcpv4_src_to_stktable_key(l4); + key = tcp_src_to_stktable_key(l4); if (!key) - return 0; /* only TCPv4 is supported right now */ + return 0; if (expr->arg_len) px = find_stktable(expr->arg.str); @@ -2893,9 +2893,9 @@ acl_fetch_src_http_err_rate(struct proxy *px, struct session *l4, void *l7, int { struct stktable_key *key; - key = tcpv4_src_to_stktable_key(l4); + key = tcp_src_to_stktable_key(l4); if (!key) - return 0; /* only TCPv4 is supported right now */ + return 0; if (expr->arg_len) px = find_stktable(expr->arg.str); @@ -2957,9 +2957,9 @@ acl_fetch_src_kbytes_in(struct proxy *px, struct session *l4, void *l7, int dir, { struct stktable_key *key; - key = tcpv4_src_to_stktable_key(l4); + key = tcp_src_to_stktable_key(l4); if (!key) - return 0; /* only TCPv4 is supported right now */ + return 0; if (expr->arg_len) px = find_stktable(expr->arg.str); @@ -3023,9 +3023,9 @@ acl_fetch_src_bytes_in_rate(struct proxy *px, struct session *l4, void *l7, int { struct stktable_key *key; - key = tcpv4_src_to_stktable_key(l4); + key = tcp_src_to_stktable_key(l4); if (!key) - return 0; /* only TCPv4 is supported right now */ + return 0; if (expr->arg_len) px = find_stktable(expr->arg.str); @@ -3087,9 +3087,9 @@ acl_fetch_src_kbytes_out(struct proxy *px, struct session *l4, void *l7, int dir { struct stktable_key *key; - key = tcpv4_src_to_stktable_key(l4); + key = tcp_src_to_stktable_key(l4); if (!key) - return 0; /* only TCPv4 is supported right now */ + return 0; if (expr->arg_len) px = find_stktable(expr->arg.str); @@ -3153,9 +3153,9 @@ acl_fetch_src_bytes_out_rate(struct proxy *px, struct session *l4, void *l7, int { struct stktable_key *key; - key = tcpv4_src_to_stktable_key(l4); + key = tcp_src_to_stktable_key(l4); if (!key) - return 0; /* only TCPv4 is supported right now */ + return 0; if (expr->arg_len) px = find_stktable(expr->arg.str); diff --git a/src/standard.c b/src/standard.c index 0e5c71ea36..d3b9ef7143 100644 --- a/src/standard.c +++ b/src/standard.c @@ -1199,6 +1199,54 @@ unsigned int full_hash(unsigned int a) return __full_hash(a); } +/* Return non-zero if IPv4 address is part of the network, + * otherwise zero. + */ +int in_net_ipv4(struct in_addr *addr, struct in_addr *mask, struct in_addr *net) +{ + return((addr->s_addr & mask->s_addr) == (net->s_addr & mask->s_addr)); +} + +/* Return non-zero if IPv6 address is part of the network, + * otherwise zero. + */ +int in_net_ipv6(struct in6_addr *addr, struct in6_addr *mask, struct in6_addr *net) +{ + int i; + + for (i = 0; i < sizeof(struct in6_addr) / sizeof(int); i++) + if (((((int *)addr)[i] & ((int *)mask)[i])) != + (((int *)net)[i] & ((int *)mask)[i])) + return 0; + return 1; +} + +/* RFC 4291 prefix */ +const char rfc4291_pfx[] = { 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFF }; + +/* Map IPv4 adress on IPv6 address, as specified in RFC 3513. */ +void v4tov6(struct in6_addr *sin6_addr, struct in_addr *sin_addr) +{ + memcpy(sin6_addr->s6_addr, rfc4291_pfx, sizeof(rfc4291_pfx)); + memcpy(sin6_addr->s6_addr+12, &sin_addr->s_addr, 4); +} + +/* Map IPv6 adress on IPv4 address, as specified in RFC 3513. + * Return true if conversion is possible and false otherwise. + */ +int v6tov4(struct in_addr *sin_addr, struct in6_addr *sin6_addr) +{ + if (memcmp(sin6_addr->s6_addr, rfc4291_pfx, sizeof(rfc4291_pfx)) == 0) { + memcpy(&(sin_addr->s_addr), &(sin6_addr->s6_addr[12]), + sizeof(struct in_addr)); + return 1; + } + + return 0; +} + /* * Local variables: * c-indent-level: 8 diff --git a/src/stick_table.c b/src/stick_table.c index 7c9ad8da0d..5e9aa35718 100644 --- a/src/stick_table.c +++ b/src/stick_table.c @@ -406,9 +406,10 @@ int stktable_init(struct stktable *t) * Configuration keywords of known table types */ struct stktable_type stktable_types[STKTABLE_TYPES] = {{ "ip", 0, 4 }, + { "ipv6", 0, 16 }, { "integer", 0, 4 }, { "string", STK_F_CUSTOM_KEYSIZE, 32 }, - { "binary", STK_F_CUSTOM_KEYSIZE, 32 } }; + { "binary", STK_F_CUSTOM_KEYSIZE, 32 } }; /* @@ -457,6 +458,25 @@ static void *k_ip2ip(union pattern_data *pdata, union stktable_key_data *kdata, return (void *)&pdata->ip.s_addr; } +static void *k_ip2ipv6(union pattern_data *pdata, union stktable_key_data *kdata, size_t *len) +{ + v4tov6(&pdata->ipv6, &pdata->ip); + return (void *)&pdata->ipv6.s6_addr; +} + +static void *k_ipv62ipv6(union pattern_data *pdata, union stktable_key_data *kdata, size_t *len) +{ + return (void *)&pdata->ipv6.s6_addr; +} + +/* +static void *k_ipv62ip(union pattern_data *pdata, union stktable_key_data *kdata, size_t *len) +{ + v6tov4(&pdata->ip, &pdata->ipv6); + return (void *)&pdata->ip.s_addr; +} +*/ + static void *k_ip2int(union pattern_data *pdata, union stktable_key_data *kdata, size_t *len) { kdata->integer = ntohl(pdata->ip.s_addr); @@ -484,6 +504,15 @@ static void *k_ip2str(union pattern_data *pdata, union stktable_key_data *kdata, return (void *)kdata->buf; } +static void *k_ipv62str(union pattern_data *pdata, union stktable_key_data *kdata, size_t *len) +{ + if (!inet_ntop(AF_INET6, &pdata->ipv6, kdata->buf, sizeof(kdata->buf))) + return NULL; + + *len = strlen((const char *)kdata->buf); + return (void *)kdata->buf; +} + static void *k_int2str(union pattern_data *pdata, union stktable_key_data *kdata, size_t *len) { void *key; @@ -504,6 +533,13 @@ static void *k_str2ip(union pattern_data *pdata, union stktable_key_data *kdata, return (void *)&kdata->ip.s_addr; } +static void *k_str2ipv6(union pattern_data *pdata, union stktable_key_data *kdata, size_t *len) +{ + if (!inet_pton(AF_INET6, pdata->str.str, &kdata->ipv6)) + return NULL; + + return (void *)&kdata->ipv6.s6_addr; +} static void *k_str2int(union pattern_data *pdata, union stktable_key_data *kdata, size_t *len) { @@ -527,15 +563,22 @@ static void *k_str2int(union pattern_data *pdata, union stktable_key_data *kdata /* NULL pointer used for impossible pattern casts */ /*****************************************************************/ +/* + * Conversions from IPv6 to IPv4 are available, but we haven't + * added them to the table since they doesn't seem sufficely + * relevant and could cause confusion in configuration. + */ + typedef void *(*pattern_to_key_fct)(union pattern_data *pdata, union stktable_key_data *kdata, size_t *len); static pattern_to_key_fct pattern_to_key[PATTERN_TYPES][STKTABLE_TYPES] = { -/* table type: IP INTEGER STRING BINARY */ -/* pattern type: IP */ { k_ip2ip, k_ip2int, k_ip2str, NULL }, -/* INTEGER */ { k_int2ip, k_int2int, k_int2str, NULL }, -/* STRING */ { k_str2ip, k_str2int, k_str2str, k_str2str }, -/* DATA */ { NULL, NULL, NULL, k_str2str }, -/* CONSTSTRING */ { k_str2ip, k_str2int, k_str2str, k_str2str }, -/* CONSTDATA */ { NULL, NULL, NULL, k_str2str }, +/* table type: IP IPV6 INTEGER STRING BINARY */ +/* pattern type: IP */ { k_ip2ip, k_ip2ipv6, k_ip2int, k_ip2str, NULL }, +/* IPV6 */ { NULL, k_ipv62ipv6, NULL, k_ipv62str, NULL }, +/* INTEGER */ { k_int2ip, NULL, k_int2int, k_int2str, NULL }, +/* STRING */ { k_str2ip, k_str2ipv6, k_str2int, k_str2str, k_str2str }, +/* DATA */ { NULL, NULL, NULL, NULL, k_str2str }, +/* CONSTSTRING */ { k_str2ip, k_str2ipv6, k_str2int, k_str2str, k_str2str }, + }; -- 2.39.5