Skip to content

Commit

Permalink
Merge pull request #1081 from tempesta-tech/ri-775-always-use-ipv6
Browse files Browse the repository at this point in the history
Use struct sockaddr_in6 for all addresses
  • Loading branch information
i-rinat authored Oct 19, 2018
2 parents f177157 + 1ba513b commit 1617736
Show file tree
Hide file tree
Showing 20 changed files with 380 additions and 339 deletions.
223 changes: 102 additions & 121 deletions tempesta_fw/addr.c

Large diffs are not rendered by default.

79 changes: 68 additions & 11 deletions tempesta_fw/addr.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
*/
#define TFW_ADDR_STR_DEF_PORT 80

#define TFW_WITH_PORT true
#define TFW_NO_PORT false

/* Maximum size of a buffer needed for tfw_addr_ntop(), including '\0'. */
#define TFW_ADDR_STR_BUF_SIZE \
sizeof("[FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255]:65535")
Expand All @@ -45,13 +48,8 @@
in6_addr.in6_u.u6_addr8[13] | \
in6_addr.in6_u.u6_addr8[14])) \

typedef union {
sa_family_t family;
struct sockaddr_in v4;
struct sockaddr_in6 v6;
struct sockaddr sa;
#define in6_prefix v6.sin6_scope_id
} TfwAddr;
#define in6_prefix sin6_scope_id
typedef struct sockaddr_in6 TfwAddr;

int tfw_addr_ifmatch(const TfwAddr *server, const TfwAddr *listener);

Expand All @@ -62,14 +60,73 @@ size_t tfw_addr_ntop(const TfwAddr *addr, char *out_buf, size_t buf_size);

/* A couple of lower-level functions faster than tfw_addr_ntop().
* Note that they don't check input arguments and don't terminate output. */
char *tfw_addr_fmt_v4(__be32 in_addr, __be16 in_port, char *out_buf);
char *tfw_addr_fmt_v6(const struct in6_addr *in6_addr, __be16 in_port,
char *out_buf);
char *tfw_addr_fmt(const TfwAddr *addr, bool print_port, char *out_buf);

static inline ssize_t
tfw_addr_sa_len(const TfwAddr *addr)
{
return (addr->family == AF_INET6) ? sizeof(addr->v6) : sizeof(addr->v4);
return sizeof(struct sockaddr_in6);
}

static inline struct sockaddr *
tfw_addr_sa(TfwAddr *addr)
{
return (struct sockaddr *)addr;
}

static inline unsigned short int
tfw_addr_sa_family(TfwAddr *addr)
{
return addr->sin6_family;
}

static inline bool
tfw_addr_is_v4mapped(const TfwAddr *addr)
{
return ipv6_addr_v4mapped(&addr->sin6_addr);
}

static inline void
tfw_addr_set_v4(TfwAddr *addr, __be32 in_addr)
{
ipv6_addr_set_v4mapped(in_addr, &addr->sin6_addr);
}

static inline __be16
tfw_addr_port(const TfwAddr *addr)
{
return addr->sin6_port;
}

static inline __be32
tfw_addr_v4addr(const TfwAddr *addr)
{
return addr->sin6_addr.s6_addr32[3];
}

static inline TfwAddr
tfw_addr_new_v4(__be32 in_addr, __be16 in_port)
{
TfwAddr addr = {
.sin6_family = AF_INET6,
.sin6_addr.s6_addr32[2] = htonl(0x0000FFFF),
.sin6_addr.s6_addr32[3] = in_addr,
.sin6_port = in_port,
};

return addr;
}

static inline TfwAddr
tfw_addr_new_v6(const struct in6_addr *in6_addr, __be16 in_port)
{
TfwAddr addr = {
.sin6_family = AF_INET6,
.sin6_addr = *in6_addr,
.sin6_port = in_port,
};

return addr;
}

static inline unsigned short
Expand Down
10 changes: 5 additions & 5 deletions tempesta_fw/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,16 +102,16 @@ tfw_client_obtain(struct sock *sk, void (*init)(TfwClient *))
TfwAddr addr;

ss_getpeername(sk, &addr);
key = hash_calc((const char *)&addr.v6.sin6_addr,
sizeof(addr.v6.sin6_addr));
key = hash_calc((const char *)&addr.sin6_addr,
sizeof(addr.sin6_addr));

hb = &cli_hash[hash_min(key, CLI_HASH_BITS)];

spin_lock(&hb->lock);

hlist_for_each_entry_safe(cli, tmp, &hb->list, hentry)
if (ipv6_addr_equal(&addr.v6.sin6_addr,
&cli->addr.v6.sin6_addr))
if (ipv6_addr_equal(&addr.sin6_addr,
&cli->addr.sin6_addr))
goto found;

if (!(cli = kmem_cache_alloc(cli_cache, GFP_ATOMIC | __GFP_ZERO))) {
Expand All @@ -127,7 +127,7 @@ tfw_client_obtain(struct sock *sk, void (*init)(TfwClient *))

TFW_INC_STAT_BH(clnt.online);
TFW_DBG("new client: cli=%p\n", cli);
TFW_DBG_ADDR6("client address", &cli->addr.v6.sin6_addr);
TFW_DBG_ADDR("client address", &cli->addr, TFW_NO_PORT);

found:
atomic_inc(&cli->conn_users);
Expand Down
14 changes: 7 additions & 7 deletions tempesta_fw/filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ static struct {
static TDB *ip_filter_db;

static unsigned long
tfw_ipv6_hash(struct in6_addr *addr)
tfw_ipv6_hash(const struct in6_addr *addr)
{
return ((unsigned long)addr->s6_addr32[0] << 32)
^ ((unsigned long)addr->s6_addr32[1] << 24)
Expand All @@ -72,22 +72,22 @@ tfw_ipv6_hash(struct in6_addr *addr)
}

void
tfw_filter_block_ip(struct in6_addr *addr)
tfw_filter_block_ip(const TfwAddr *addr)
{
TfwFRule rule = {
.addr = *addr,
.addr = addr->sin6_addr,
.action = TFW_F_DROP,
};
unsigned long key = tfw_ipv6_hash(addr);
unsigned long key = tfw_ipv6_hash(&addr->sin6_addr);
size_t len = sizeof(rule);

TFW_DBG_ADDR6("filter: block", addr);
TFW_DBG_ADDR("filter: block", addr, TFW_NO_PORT);

/* TODO create records on all NUMA nodes. */
if (!tdb_entry_create(ip_filter_db, key, &rule, &len)) {
TFW_WARN_ADDR6("cannot create blocking rule", addr);
TFW_WARN_ADDR("cannot create blocking rule", addr, TFW_NO_PORT);
} else {
TFW_DBG_ADDR6("block client", addr);
TFW_DBG_ADDR("block client", addr, TFW_NO_PORT);
}
}
EXPORT_SYMBOL(tfw_filter_block_ip);
Expand Down
4 changes: 2 additions & 2 deletions tempesta_fw/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
#ifndef __TFW_FILTER_H__
#define __TFW_FILTER_H__

#include <linux/in6.h>
#include "addr.h"

void tfw_filter_block_ip(struct in6_addr *addr);
void tfw_filter_block_ip(const TfwAddr *addr);

#endif /* __TFW_FILTER_H__ */
31 changes: 18 additions & 13 deletions tempesta_fw/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@

#include "sync_socket.h"

#define TFW_WARN_ADDR_STATUS(msg, addr_ptr, status) \
TFW_WITH_ADDR_FMT(addr_ptr, addr_str, \
#define TFW_WARN_ADDR_STATUS(msg, addr_ptr, print_port, status) \
TFW_WITH_ADDR_FMT(addr_ptr, print_port, addr_str, \
TFW_WARN("%s, status %d: %s\n", \
msg, status, addr_str))

Expand Down Expand Up @@ -904,8 +904,10 @@ tfw_http_error_resp_switch(TfwHttpReq *req, int status)
void
tfw_http_send_resp(TfwHttpReq *req, int status, const char *reason)
{
if (!(tfw_blk_flags & TFW_BLK_ERR_NOLOG))
TFW_WARN_ADDR_STATUS(reason, &req->conn->peer->addr, status);
if (!(tfw_blk_flags & TFW_BLK_ERR_NOLOG)) {
TFW_WARN_ADDR_STATUS(reason, &req->conn->peer->addr,
TFW_WITH_PORT, status);
}
tfw_http_error_resp_switch(req, status);
}

Expand All @@ -925,8 +927,9 @@ tfw_http_hm_suspend(TfwHttpResp *resp, TfwServer *srv)
flags | TFW_SRV_F_SUSPEND);
if (likely(old_flags == flags)) {
TFW_WARN_ADDR_STATUS("server has been suspended: limit "
"for bad responses is exceeded",
&srv->addr, resp->status);
"for bad responses is exceeded",
&srv->addr, TFW_WITH_PORT,
resp->status);
break;
}
flags = old_flags;
Expand Down Expand Up @@ -1112,8 +1115,8 @@ tfw_http_req_fwd_send(TfwSrvConn *srv_conn, TfwServer *srv,
WARN_ON_ONCE(req->pair);
tfw_http_msg_free((TfwHttpMsg *)req);
TFW_WARN_ADDR("Unable to send health"
" monitoring request to server",
&srv_conn->peer->addr);
" monitoring request to server",
&srv_conn->peer->addr, TFW_WITH_PORT);
} else {
tfw_http_req_err(srv_conn, req, eq, 500,
"request dropped: forwarding error");
Expand Down Expand Up @@ -1419,8 +1422,9 @@ tfw_http_req_resched(TfwHttpReq *req, TfwServer *srv, struct list_head *eq)
list_del_init(&req->fwd_list);
tfw_http_conn_msg_free((TfwHttpMsg *)req);
TFW_WARN_ADDR("Unable to find connection to"
" reschedule health monitoring"
" request on server", &srv->addr);
" reschedule health monitoring"
" request on server", &srv->addr,
TFW_WITH_PORT);
return;
}
} else if (!(sch_conn = tfw_http_get_srv_conn((TfwMsg *)req))) {
Expand Down Expand Up @@ -2368,7 +2372,7 @@ tfw_http_cli_error_resp_and_log(bool reply, bool nolog, TfwHttpReq *req,
int status, const char *msg)
{
if (!nolog)
TFW_WARN_ADDR(msg, &req->conn->peer->addr);
TFW_WARN_ADDR(msg, &req->conn->peer->addr, TFW_WITH_PORT);

if (reply) {
TfwCliConn *cli_conn = (TfwCliConn *)req->conn;
Expand All @@ -2388,7 +2392,7 @@ tfw_http_srv_error_resp_and_log(bool reply, bool nolog, TfwHttpReq *req,
int status, const char *msg)
{
if (!nolog)
TFW_WARN_ADDR(msg, &req->conn->peer->addr);
TFW_WARN_ADDR(msg, &req->conn->peer->addr, TFW_WITH_PORT);

if (reply)
tfw_http_req_mark_error(req, status);
Expand Down Expand Up @@ -3395,7 +3399,8 @@ tfw_http_hm_srv_send(TfwServer *srv, char *data, unsigned long len)
srv_conn = srv->sg->sched->sched_srv_conn((TfwMsg *)req, srv);
if (!srv_conn) {
TFW_WARN_ADDR("Unable to find connection for health"
" monitoring of backend server", &srv->addr);
" monitoring of backend server", &srv->addr,
TFW_WITH_PORT);
goto cleanup;
}

Expand Down
8 changes: 4 additions & 4 deletions tempesta_fw/http_limits.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ int prio0, prio1, prio3;
: tfw_vhost_global_frang_cfg()->member)

#define frang_msg(check, addr, fmt, ...) \
TFW_WARN_MOD_ADDR6(frang, check, addr, fmt, ##__VA_ARGS__)
TFW_WARN_MOD_ADDR(frang, check, addr, TFW_NO_PORT, fmt, ##__VA_ARGS__)

#define frang_limmsg(lim_name, curr_val, lim, addr) \
frang_msg(lim_name " exceeded", (addr), ": %ld (lim=%ld)\n", \
Expand All @@ -265,7 +265,7 @@ int prio0, prio1, prio3;
#define frang_dbg(fmt_msg, addr, ...) \
do { \
char abuf[TFW_ADDR_STR_BUF_SIZE] = {0}; \
tfw_addr_fmt_v6(&(addr)->v6.sin6_addr, 0, abuf); \
tfw_addr_fmt(addr, TFW_NO_PORT, abuf); \
TFW_DBG("frang: " fmt_msg, abuf, ##__VA_ARGS__); \
} while (0)
#else
Expand Down Expand Up @@ -361,7 +361,7 @@ frang_conn_new(struct sock *sk)

r = frang_conn_limit(ra, sk, conf);
if (r == TFW_BLOCK && conf->ip_block) {
tfw_filter_block_ip(&cli->addr.v6.sin6_addr);
tfw_filter_block_ip(&cli->addr);
tfw_client_put(cli);
}

Expand Down Expand Up @@ -1048,7 +1048,7 @@ frang_http_req_handler(void *obj, const TfwFsmData *data)

r = frang_http_req_process(ra, conn, data);
if (r == TFW_BLOCK && ip_block)
tfw_filter_block_ip(&FRANG_ACC2CLI(ra)->addr.v6.sin6_addr);
tfw_filter_block_ip(&FRANG_ACC2CLI(ra)->addr);

return r;
}
Expand Down
3 changes: 2 additions & 1 deletion tempesta_fw/http_sched_hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ __calc_srv_hash(TfwServer *srv)
* - No structure fields (e.g. sin6_flowinfo) are changed if we
* re-connect to the same server.
*/
hash = hash_calc((char *)&srv->addr, tfw_addr_sa_len(&srv->addr));
hash = hash_calc((char *)tfw_addr_sa(&srv->addr),
tfw_addr_sa_len(&srv->addr));
/*
* If TfwAddr represents IPv4 address @tdb_hash_calc() will always
* generate a 32-bit value. In the same time IPv6 servers are likely to
Expand Down
16 changes: 9 additions & 7 deletions tempesta_fw/http_sess.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ tfw_http_sticky_get(TfwHttpReq *req, TfwStr *cookie_val)
do { \
char abuf[TFW_ADDR_STR_BUF_SIZE] = {0}; \
char hbuf[STICKY_KEY_MAXLEN * 2] = {0}; \
tfw_addr_fmt_v6(&(addr)->v6.sin6_addr, 0, abuf); \
tfw_addr_fmt(addr, TFW_NO_PORT, abuf); \
bin2hex(hbuf, tfw_sticky_key, STICKY_KEY_MAXLEN); \
TFW_DBG("http_sess: calculate sticky cookie for %s," \
" ts=%#lx(now=%#lx)...\n", abuf, (sv)->ts, jiffies); \
Expand All @@ -360,7 +360,7 @@ do { \
static int
__sticky_calc(TfwHttpReq *req, StickyVal *sv)
{
int r, addr_len;
int r;
TfwStr ua_value = { 0 };
TfwAddr *addr = &req->conn->peer->addr;
TfwStr *hdr, *c, *end;
Expand All @@ -372,16 +372,17 @@ __sticky_calc(TfwHttpReq *req, StickyVal *sv)
tfw_http_msg_clnthdr_val(hdr, TFW_HTTP_HDR_USER_AGENT,
&ua_value);

addr_len = tfw_addr_sa_len(addr);

shash_desc->tfm = tfw_sticky_shash;
shash_desc->flags = 0;

TFW_DBG_PRINT_STICKY_COOKIE(addr, &ua_value, sv);

if ((r = crypto_shash_init(shash_desc)))
return r;
if ((r = crypto_shash_update(shash_desc, (u8 *)&addr->sa, addr_len)))

r = crypto_shash_update(shash_desc, (u8 *)tfw_addr_sa(addr),
tfw_addr_sa_len(addr));
if (r)
return r;
if (ua_value.len) {
TFW_STR_FOR_EACH_CHUNK(c, &ua_value, end) {
Expand Down Expand Up @@ -494,7 +495,8 @@ tfw_http_redir_mark_get(TfwHttpReq *req, TfwStr *out_val)
}

#define sess_warn(check, addr, fmt, ...) \
TFW_WARN_MOD_ADDR6(http_sess, check, addr, fmt, ##__VA_ARGS__)
TFW_WARN_MOD_ADDR(http_sess, check, addr, TFW_NO_PORT, fmt, \
##__VA_ARGS__)

/* The set of macros for parsing hex strings of following format:
*
Expand Down Expand Up @@ -604,7 +606,7 @@ tfw_http_sess_check_redir_mark(TfwHttpReq *req, RedirMarkVal *mv)
|| (tfw_cfg_sticky.tmt_sec
&& mv->ts + HZ * tfw_cfg_sticky.tmt_sec < jiffies))
{
tfw_filter_block_ip(&req->conn->peer->addr.v6.sin6_addr);
tfw_filter_block_ip(&req->conn->peer->addr);
return TFW_HTTP_SESS_VIOLATE;
}
bzero_fast(mv->hmac, sizeof(mv->hmac));
Expand Down
Loading

0 comments on commit 1617736

Please sign in to comment.