mirror of https://github.com/sipwise/rtpengine.git
Change-Id: I8e2b47bf34206ed5cc369649bf8ef875ac271169changes/96/15296/18
parent
dd338975f6
commit
e7d75bd275
@ -0,0 +1,378 @@
|
||||
#include "iptables.h"
|
||||
|
||||
char *g_iptables_chain;
|
||||
int (*iptables_add_rule)(const socket_t *local_sock, const str *comment);
|
||||
int (*iptables_del_rule)(const socket_t *local_sock);
|
||||
|
||||
#ifdef WITH_IPTABLES_OPTION
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <libiptc/libiptc.h>
|
||||
#include <libiptc/libip6tc.h>
|
||||
#include <libiptc/libxtc.h>
|
||||
#include <linux/netfilter/xt_comment.h>
|
||||
#include <glib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/file.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include "aux.h"
|
||||
#include "log.h"
|
||||
#include "socket.h"
|
||||
#include "str.h"
|
||||
|
||||
#undef __ALIGN_KERNEL
|
||||
#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (__typeof(x))(a) - 1)
|
||||
#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
||||
#undef XT_ALIGN
|
||||
#define XT_ALIGN(s) __ALIGN_KERNEL((s), __alignof__(struct _xt_align))
|
||||
|
||||
#ifndef XT_LOCK_NAME
|
||||
#define XT_LOCK_NAME "/run/xtables.lock"
|
||||
#endif
|
||||
|
||||
|
||||
struct ipt_matches {
|
||||
struct xt_entry_match udp_match;
|
||||
struct xt_udp udp;
|
||||
struct xt_entry_match comment_match;
|
||||
struct xt_comment_info comment;
|
||||
struct xt_standard_target target;
|
||||
};
|
||||
struct ipv4_ipt_entry {
|
||||
struct ipt_entry entry;
|
||||
struct ipt_matches matches;
|
||||
};
|
||||
struct ipv6_ipt_entry {
|
||||
struct ip6t_entry entry;
|
||||
struct ipt_matches matches;
|
||||
};
|
||||
|
||||
|
||||
static mutex_t __xt_lock;
|
||||
static int __xt_lock_fd = -1;
|
||||
|
||||
|
||||
|
||||
static void xt_lock(void) {
|
||||
mutex_lock(&__xt_lock);
|
||||
|
||||
__xt_lock_fd = open(XT_LOCK_NAME, O_CREAT, 0600);
|
||||
if (__xt_lock_fd == -1) {
|
||||
ilog(LOG_WARN, "Could not open xtables lock file '%s': %s", XT_LOCK_NAME, strerror(errno));
|
||||
// as per iptables source code, continue anyway
|
||||
return;
|
||||
}
|
||||
|
||||
if (flock(__xt_lock_fd, LOCK_EX)) {
|
||||
ilog(LOG_WARN, "Failed to acquire lock file '%s': %s", XT_LOCK_NAME, strerror(errno));
|
||||
close(__xt_lock_fd);
|
||||
__xt_lock_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void xt_unlock(void) {
|
||||
if (__xt_lock_fd != -1)
|
||||
close(__xt_lock_fd);
|
||||
__xt_lock_fd = -1;
|
||||
mutex_unlock(&__xt_lock);
|
||||
}
|
||||
|
||||
static void ip46tables_fill_matches(struct ipt_matches *matches, const socket_t *local_sock,
|
||||
const str *comment)
|
||||
{
|
||||
matches->target.target.u.user.target_size = XT_ALIGN(sizeof(struct xt_standard_target));
|
||||
strcpy(matches->target.target.u.user.name, "ACCEPT");
|
||||
|
||||
strcpy(matches->udp_match.u.user.name, "udp");
|
||||
matches->udp_match.u.match_size = XT_ALIGN(sizeof(struct xt_entry_match)) + XT_ALIGN(sizeof(struct xt_udp));
|
||||
matches->udp.dpts[0] = matches->udp.dpts[1] = local_sock->local.port;
|
||||
matches->udp.spts[0] = 0;
|
||||
matches->udp.spts[1] = 0xffff;
|
||||
|
||||
matches->comment_match.u.match_size = XT_ALIGN(sizeof(struct xt_entry_match))
|
||||
+ XT_ALIGN(sizeof(struct xt_comment_info));
|
||||
strcpy(matches->comment_match.u.user.name, "comment");
|
||||
if (comment)
|
||||
str_ncpy(matches->comment.comment, sizeof(matches->comment.comment), comment);
|
||||
}
|
||||
|
||||
static void ip4_fill_entry(struct ipv4_ipt_entry *entry, const socket_t *local_sock, const str *comment) {
|
||||
ZERO(*entry);
|
||||
entry->entry.ip.proto = IPPROTO_UDP;
|
||||
entry->entry.ip.dst = local_sock->local.address.u.ipv4;
|
||||
memset(&entry->entry.ip.dmsk, 0xff, sizeof(entry->entry.ip.dmsk));
|
||||
entry->entry.target_offset = G_STRUCT_OFFSET(struct ipv4_ipt_entry, matches.target);
|
||||
|
||||
ip46tables_fill_matches(&entry->matches, local_sock, comment);
|
||||
|
||||
entry->entry.next_offset = entry->entry.target_offset + entry->matches.target.target.u.user.target_size;
|
||||
}
|
||||
static void ip6_fill_entry(struct ipv6_ipt_entry *entry, const socket_t *local_sock, const str *comment) {
|
||||
ZERO(*entry);
|
||||
entry->entry.ipv6.proto = IPPROTO_UDP;
|
||||
entry->entry.ipv6.dst = local_sock->local.address.u.ipv6;
|
||||
entry->entry.ipv6.flags |= IP6T_F_PROTO;
|
||||
memset(&entry->entry.ipv6.dmsk, 0xff, sizeof(entry->entry.ipv6.dmsk));
|
||||
entry->entry.target_offset = G_STRUCT_OFFSET(struct ipv6_ipt_entry, matches.target);
|
||||
|
||||
ip46tables_fill_matches(&entry->matches, local_sock, comment);
|
||||
|
||||
entry->entry.next_offset = entry->entry.target_offset + entry->matches.target.target.u.user.target_size;
|
||||
}
|
||||
|
||||
static const char *ip4tables_add_rule(const socket_t *local_sock, const str *comment) {
|
||||
struct xtc_handle *h;
|
||||
struct ipv4_ipt_entry entry;
|
||||
const char *err;
|
||||
|
||||
xt_lock();
|
||||
|
||||
err = "could not initialize iptables";
|
||||
h = iptc_init("filter");
|
||||
if (!h)
|
||||
goto err2;
|
||||
|
||||
ip4_fill_entry(&entry, local_sock, comment);
|
||||
|
||||
err = "failed to append iptables entry";
|
||||
if (!iptc_append_entry(g_iptables_chain, &entry.entry, h))
|
||||
goto err;
|
||||
err = "failed to commit iptables changes";
|
||||
if (!iptc_commit(h))
|
||||
goto err;
|
||||
|
||||
err = NULL;
|
||||
|
||||
err:
|
||||
iptc_free(h);
|
||||
err2:
|
||||
xt_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
static const char *ip6tables_add_rule(const socket_t *local_sock, const str *comment) {
|
||||
struct xtc_handle *h;
|
||||
struct ipv6_ipt_entry entry;
|
||||
const char *err;
|
||||
|
||||
xt_lock();
|
||||
|
||||
err = "could not initialize ip6tables";
|
||||
h = ip6tc_init("filter");
|
||||
if (!h)
|
||||
goto err2;
|
||||
|
||||
ip6_fill_entry(&entry, local_sock, comment);
|
||||
|
||||
err = "failed to append ip6tables entry";
|
||||
if (!ip6tc_append_entry(g_iptables_chain, &entry.entry, h))
|
||||
goto err;
|
||||
err = "failed to commit ip6tables changes";
|
||||
if (!ip6tc_commit(h))
|
||||
goto err;
|
||||
|
||||
err = NULL;
|
||||
|
||||
err:
|
||||
ip6tc_free(h);
|
||||
err2:
|
||||
xt_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
static const char *ip4tables_del_rule(const socket_t *local_sock) {
|
||||
struct xtc_handle *h;
|
||||
struct ipv4_ipt_entry entry, mask;
|
||||
const char *err;
|
||||
|
||||
xt_lock();
|
||||
|
||||
err = "could not initialize iptables";
|
||||
h = iptc_init("filter");
|
||||
if (!h)
|
||||
goto err2;
|
||||
|
||||
ip4_fill_entry(&entry, local_sock, NULL);
|
||||
|
||||
// match everything except the comment
|
||||
memset(&mask, 0, sizeof(mask));
|
||||
memset(&mask.entry, 0xff, sizeof(mask.entry));
|
||||
memset(&mask.matches.udp_match, 0xff, sizeof(mask.matches.udp_match));
|
||||
memset(&mask.matches.udp, 0xff, sizeof(mask.matches.udp));
|
||||
memset(&mask.matches.comment_match, 0xff, sizeof(mask.matches.comment_match));
|
||||
memset(&mask.matches.target, 0xff, sizeof(mask.matches.target));
|
||||
|
||||
err = "failed to delete iptables entry";
|
||||
if (!iptc_delete_entry(g_iptables_chain, &entry.entry, (unsigned char *) &mask, h))
|
||||
goto err;
|
||||
err = "failed to commit iptables changes";
|
||||
if (!iptc_commit(h))
|
||||
goto err;
|
||||
|
||||
err = NULL;
|
||||
|
||||
err:
|
||||
iptc_free(h);
|
||||
err2:
|
||||
xt_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
static const char *ip6tables_del_rule(const socket_t *local_sock) {
|
||||
struct xtc_handle *h;
|
||||
struct ipv6_ipt_entry entry, mask;
|
||||
const char *err;
|
||||
|
||||
xt_lock();
|
||||
|
||||
err = "could not initialize ip6tables";
|
||||
h = ip6tc_init("filter");
|
||||
if (!h)
|
||||
goto err2;
|
||||
|
||||
ip6_fill_entry(&entry, local_sock, NULL);
|
||||
|
||||
// match everything except the comment
|
||||
memset(&mask, 0, sizeof(mask));
|
||||
memset(&mask.entry, 0xff, sizeof(mask.entry));
|
||||
memset(&mask.matches.udp_match, 0xff, sizeof(mask.matches.udp_match));
|
||||
memset(&mask.matches.udp, 0xff, sizeof(mask.matches.udp));
|
||||
memset(&mask.matches.comment_match, 0xff, sizeof(mask.matches.comment_match));
|
||||
memset(&mask.matches.target, 0xff, sizeof(mask.matches.target));
|
||||
|
||||
err = "failed to delete ip6tables entry";
|
||||
if (!ip6tc_delete_entry(g_iptables_chain, &entry.entry, (unsigned char *) &mask, h))
|
||||
goto err;
|
||||
err = "failed to commit ip6tables changes";
|
||||
if (!ip6tc_commit(h))
|
||||
goto err;
|
||||
|
||||
err = NULL;
|
||||
|
||||
err:
|
||||
ip6tc_free(h);
|
||||
err2:
|
||||
xt_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __iptables_add_rule(const socket_t *local_sock, const str *comment) {
|
||||
const char *err;
|
||||
|
||||
switch (local_sock->family->af) {
|
||||
case AF_INET:
|
||||
err = ip4tables_add_rule(local_sock, comment);
|
||||
break;
|
||||
case AF_INET6:
|
||||
err = ip6tables_add_rule(local_sock, comment);
|
||||
break;
|
||||
default:
|
||||
err = "unsupported socket family";
|
||||
break;
|
||||
};
|
||||
|
||||
if (err)
|
||||
ilog(LOG_ERROR, "Error adding iptables rule (for '" STR_FORMAT "'): %s (%s)",
|
||||
STR_FMT(comment), err, strerror(errno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int __iptables_del_rule(const socket_t *local_sock) {
|
||||
const char *err;
|
||||
|
||||
switch (local_sock->family->af) {
|
||||
case AF_INET:
|
||||
err = ip4tables_del_rule(local_sock);
|
||||
break;
|
||||
case AF_INET6:
|
||||
err = ip6tables_del_rule(local_sock);
|
||||
break;
|
||||
default:
|
||||
err = "unsupported socket family";
|
||||
break;
|
||||
};
|
||||
|
||||
if (err)
|
||||
ilog(LOG_ERROR, "Error deleting iptables rule: %s (%s)",
|
||||
err, strerror(errno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // WITH_IPTABLES_OPTION
|
||||
|
||||
static int __iptables_stub(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void iptables_init(void) {
|
||||
if (g_iptables_chain && !g_iptables_chain[0])
|
||||
g_iptables_chain = NULL;
|
||||
|
||||
if (!g_iptables_chain) {
|
||||
iptables_add_rule = (void *) __iptables_stub;
|
||||
iptables_del_rule = (void *) __iptables_stub;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef WITH_IPTABLES_OPTION
|
||||
|
||||
mutex_init(&__xt_lock);
|
||||
iptables_add_rule = __iptables_add_rule;
|
||||
iptables_del_rule = __iptables_del_rule;
|
||||
|
||||
// flush chains
|
||||
|
||||
const char *err;
|
||||
struct xtc_handle *h;
|
||||
|
||||
xt_lock();
|
||||
|
||||
err = "could not initialize iptables";
|
||||
h = iptc_init("filter");
|
||||
if (!h)
|
||||
goto out;
|
||||
err = "could not flush iptables chain";
|
||||
if (!iptc_flush_entries(g_iptables_chain, h))
|
||||
goto err2;
|
||||
err = "could not commit iptables changes";
|
||||
if (!iptc_commit(h))
|
||||
goto err2;
|
||||
iptc_free(h);
|
||||
|
||||
err = "could not initialize ip6tables";
|
||||
h = ip6tc_init("filter");
|
||||
if (!h)
|
||||
goto out;
|
||||
err = "could not flush ip6tables chain";
|
||||
if (!ip6tc_flush_entries(g_iptables_chain, h))
|
||||
goto err1;
|
||||
err = "could not commit iptables changes";
|
||||
if (!ip6tc_commit(h))
|
||||
goto err1;
|
||||
ip6tc_free(h);
|
||||
|
||||
err = NULL;
|
||||
goto out;
|
||||
|
||||
err1:
|
||||
ip6tc_free(h);
|
||||
goto out;
|
||||
err2:
|
||||
iptc_free(h);
|
||||
goto out;
|
||||
out:
|
||||
xt_unlock();
|
||||
if (err)
|
||||
ilog(LOG_ERROR, "Failed to flush iptables chain: %s (%s)", err, strerror(errno));
|
||||
|
||||
#endif // WITH_IPTABLES_OPTION
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
#ifndef _IPTABLES_H_
|
||||
#define _IPTABLES_H_
|
||||
|
||||
|
||||
#include "socket.h"
|
||||
#include "str.h"
|
||||
|
||||
|
||||
extern char *g_iptables_chain;
|
||||
|
||||
void iptables_init(void);
|
||||
extern int (*iptables_add_rule)(const socket_t *local_sock, const str *comment);
|
||||
extern int (*iptables_del_rule)(const socket_t *local_sock);
|
||||
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in new issue