forecast: Fix alignment when adding rules

Basically the same issue as with the connmark plugin.

Fixes #1212.
This commit is contained in:
Tobias Brunner
2016-03-03 17:20:37 +01:00
parent c4cb652a56
commit 444565325a
+136 -117
View File
@@ -1,4 +1,7 @@
/* /*
* Copyright (C) 2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2010-2014 Martin Willi * Copyright (C) 2010-2014 Martin Willi
* Copyright (C) 2010-2014 revosec AG * Copyright (C) 2010-2014 revosec AG
* *
@@ -25,6 +28,15 @@
#include <collections/hashtable.h> #include <collections/hashtable.h>
#include <threading/rwlock.h> #include <threading/rwlock.h>
/**
* Add a struct at the current position in the buffer
*/
#define ADD_STRUCT(pos, st, ...) ({\
typeof(pos) _cur = pos; pos += XT_ALIGN(sizeof(st));\
*(st*)_cur = (st){ __VA_ARGS__ };\
(st*)_cur;\
})
typedef struct private_forecast_listener_t private_forecast_listener_t; typedef struct private_forecast_listener_t private_forecast_listener_t;
/** /**
@@ -164,60 +176,60 @@ static bool manage_rule(struct iptc_handle *ipth, const char *chain,
static bool manage_pre_esp_in_udp(struct iptc_handle *ipth, static bool manage_pre_esp_in_udp(struct iptc_handle *ipth,
entry_t *entry, bool add) entry_t *entry, bool add)
{ {
struct { u_int16_t match_size = XT_ALIGN(sizeof(struct ipt_entry_match)) +
struct ipt_entry e; XT_ALIGN(sizeof(struct xt_udp));
struct ipt_entry_match m; u_int16_t target_offset = XT_ALIGN(sizeof(struct ipt_entry)) + match_size;
struct xt_udp udp; u_int16_t target_size = XT_ALIGN(sizeof(struct ipt_entry_target)) +
struct ipt_entry_target t; XT_ALIGN(sizeof(struct xt_mark_tginfo2));
struct xt_mark_tginfo2 tm; u_int16_t entry_size = target_offset + target_size;
} ipt = { u_char ipt[entry_size], *pos = ipt;
.e = { struct ipt_entry *e;
.target_offset = XT_ALIGN(sizeof(ipt.e) + sizeof(ipt.m) +
sizeof(ipt.udp)),
.next_offset = sizeof(ipt),
.ip = {
.proto = IPPROTO_UDP,
},
},
.m = {
.u = {
.user = {
.match_size = XT_ALIGN(sizeof(ipt.m) + sizeof(ipt.udp)),
.name = "udp",
},
},
},
.udp = {
.spts = {
entry->rhost->get_port(entry->rhost),
entry->rhost->get_port(entry->lhost)
},
.dpts = {
entry->lhost->get_port(entry->lhost),
entry->lhost->get_port(entry->lhost)
},
},
.t = {
.u = {
.user = {
.target_size = XT_ALIGN(sizeof(ipt.t) + sizeof(ipt.tm)),
.name = "MARK",
.revision = 2,
},
},
},
.tm = {
.mark = entry->mark,
.mask = ~0,
},
};
if (!host2in(entry->lhost, &ipt.e.ip.dst, &ipt.e.ip.dmsk) || memset(ipt, 0, sizeof(ipt));
!host2in(entry->rhost, &ipt.e.ip.src, &ipt.e.ip.smsk)) e = ADD_STRUCT(pos, struct ipt_entry,
.target_offset = target_offset,
.next_offset = entry_size,
.ip = {
.proto = IPPROTO_UDP,
},
);
if (!host2in(entry->lhost, &e->ip.dst, &e->ip.dmsk) ||
!host2in(entry->rhost, &e->ip.src, &e->ip.smsk))
{ {
return FALSE; return FALSE;
} }
return manage_rule(ipth, "PREROUTING", add, &ipt.e); ADD_STRUCT(pos, struct ipt_entry_match,
.u = {
.user = {
.match_size = match_size,
.name = "udp",
},
},
);
ADD_STRUCT(pos, struct xt_udp,
.spts = {
entry->rhost->get_port(entry->rhost),
entry->rhost->get_port(entry->lhost)
},
.dpts = {
entry->lhost->get_port(entry->lhost),
entry->lhost->get_port(entry->lhost)
},
);
ADD_STRUCT(pos, struct ipt_entry_target,
.u = {
.user = {
.target_size = target_size,
.name = "MARK",
.revision = 2,
},
},
);
ADD_STRUCT(pos, struct xt_mark_tginfo2,
.mark = entry->mark,
.mask = ~0,
);
return manage_rule(ipth, "PREROUTING", add, e);
} }
/** /**
@@ -225,53 +237,53 @@ static bool manage_pre_esp_in_udp(struct iptc_handle *ipth,
*/ */
static bool manage_pre_esp(struct iptc_handle *ipth, entry_t *entry, bool add) static bool manage_pre_esp(struct iptc_handle *ipth, entry_t *entry, bool add)
{ {
struct { u_int16_t match_size = XT_ALIGN(sizeof(struct ipt_entry_match)) +
struct ipt_entry e; XT_ALIGN(sizeof(struct xt_esp));
struct ipt_entry_match m; u_int16_t target_offset = XT_ALIGN(sizeof(struct ipt_entry)) + match_size;
struct xt_esp esp; u_int16_t target_size = XT_ALIGN(sizeof(struct ipt_entry_target)) +
struct ipt_entry_target t; XT_ALIGN(sizeof(struct xt_mark_tginfo2));
struct xt_mark_tginfo2 tm; u_int16_t entry_size = target_offset + target_size;
} ipt = { u_char ipt[entry_size], *pos = ipt;
.e = { struct ipt_entry *e;
.target_offset = XT_ALIGN(sizeof(ipt.e) + sizeof(ipt.m) +
sizeof(ipt.esp)),
.next_offset = sizeof(ipt),
.ip = {
.proto = IPPROTO_ESP,
},
},
.m = {
.u = {
.user = {
.match_size = XT_ALIGN(sizeof(ipt.m) + sizeof(ipt.esp)),
.name = "esp",
},
},
},
.esp = {
.spis = { htonl(entry->spi), htonl(entry->spi) },
},
.t = {
.u = {
.user = {
.target_size = XT_ALIGN(sizeof(ipt.t) + sizeof(ipt.tm)),
.name = "MARK",
.revision = 2,
},
},
},
.tm = {
.mark = entry->mark,
.mask = ~0,
},
};
if (!host2in(entry->lhost, &ipt.e.ip.dst, &ipt.e.ip.dmsk) || memset(ipt, 0, sizeof(ipt));
!host2in(entry->rhost, &ipt.e.ip.src, &ipt.e.ip.smsk)) e = ADD_STRUCT(pos, struct ipt_entry,
.target_offset = target_offset,
.next_offset = entry_size,
.ip = {
.proto = IPPROTO_ESP,
},
);
if (!host2in(entry->lhost, &e->ip.dst, &e->ip.dmsk) ||
!host2in(entry->rhost, &e->ip.src, &e->ip.smsk))
{ {
return FALSE; return FALSE;
} }
return manage_rule(ipth, "PREROUTING", add, &ipt.e); ADD_STRUCT(pos, struct ipt_entry_match,
.u = {
.user = {
.match_size = match_size,
.name = "esp",
},
},
);
ADD_STRUCT(pos, struct xt_esp,
.spis = { htonl(entry->spi), htonl(entry->spi) },
);
ADD_STRUCT(pos, struct ipt_entry_target,
.u = {
.user = {
.target_size = target_size,
.name = "MARK",
.revision = 2,
},
},
);
ADD_STRUCT(pos, struct xt_mark_tginfo2,
.mark = entry->mark,
.mask = ~0,
);
return manage_rule(ipth, "PREROUTING", add, e);
} }
/** /**
@@ -291,45 +303,52 @@ static bool manage_pre(struct iptc_handle *ipth, entry_t *entry, bool add)
*/ */
static bool manage_out(struct iptc_handle *ipth, entry_t *entry, bool add) static bool manage_out(struct iptc_handle *ipth, entry_t *entry, bool add)
{ {
struct { u_int16_t target_offset = XT_ALIGN(sizeof(struct ipt_entry));
struct ipt_entry e; u_int16_t target_size = XT_ALIGN(sizeof(struct ipt_entry_target)) +
struct ipt_entry_target t; XT_ALIGN(sizeof(struct xt_mark_tginfo2));
struct xt_mark_tginfo2 m; u_int16_t entry_size = target_offset + target_size;
} ipt = { u_char ipt[entry_size], *pos = ipt;
.e = { struct ipt_entry *e;
.target_offset = XT_ALIGN(sizeof(ipt.e)),
.next_offset = sizeof(ipt), memset(ipt, 0, sizeof(ipt));
e = ADD_STRUCT(pos, struct ipt_entry,
.target_offset = target_offset,
.next_offset = entry_size,
);
ADD_STRUCT(pos, struct ipt_entry_target,
.u = {
.user = {
.target_size = target_size,
.name = "MARK",
.revision = 2,
},
}, },
.t = { );
.u.user.target_size = XT_ALIGN(sizeof(ipt.t) + sizeof(ipt.m)), ADD_STRUCT(pos, struct xt_mark_tginfo2,
.u.user.name = "MARK", .mark = entry->mark,
.u.user.revision = 2, .mask = ~0,
}, );
.m = {
.mark = entry->mark,
.mask = ~0,
},
};
enumerator_t *enumerator; enumerator_t *enumerator;
traffic_selector_t *ts; traffic_selector_t *ts;
enumerator = array_create_enumerator(entry->rts); enumerator = array_create_enumerator(entry->rts);
while (enumerator->enumerate(enumerator, &ts)) while (enumerator->enumerate(enumerator, &ts))
{ {
if (!ts2in(ts, &ipt.e.ip.dst, &ipt.e.ip.dmsk)) if (!ts2in(ts, &e->ip.dst, &e->ip.dmsk))
{ {
continue; continue;
} }
if (ipt.e.ip.dst.s_addr == 0xffffffff || if (e->ip.dst.s_addr == 0xffffffff ||
ipt.e.ip.dst.s_addr == entry->broadcast || e->ip.dst.s_addr == entry->broadcast ||
memeq(&ipt.e.ip.dst.s_addr, "\xe0", 1)) memeq(&e->ip.dst.s_addr, "\xe0", 1))
{ {
/* skip broadcast/multicast selectors, they are shared and the mark /* skip broadcast/multicast selectors, they are shared and the mark
* is set by the socket we use for reinjection */ * is set by the socket we use for reinjection */
continue; continue;
} }
if (!manage_rule(ipth, "PREROUTING", add, &ipt.e) || if (!manage_rule(ipth, "PREROUTING", add, e) ||
!manage_rule(ipth, "OUTPUT", add, &ipt.e)) !manage_rule(ipth, "OUTPUT", add, e))
{ {
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
return FALSE; return FALSE;