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 */
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;
}
/* 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 */
/* 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 */
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;
/* 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*/
};
/* 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 */
/* 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 */
};
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);
}
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);
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();
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 },
};
* 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)
* 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)
* 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);
}
* 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);
}
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)
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
}
-/* 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)
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,
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;
}
/* Note: must not be declared <const> 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 },
{
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);
{
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);
{
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);
{
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);
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);
{
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);
{
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);
{
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);
{
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);
{
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);
{
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);
{
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);
{
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);
{
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);
{
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);
{
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);
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
* 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 } };
/*
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);
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;
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)
{
/* 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 },
+
};