|
|
|
|
@ -10,6 +10,7 @@
|
|
|
|
|
#include <linux/version.h>
|
|
|
|
|
#include <net/icmp.h>
|
|
|
|
|
#include <net/ip.h>
|
|
|
|
|
#include <net/ipv6.h>
|
|
|
|
|
#include <net/tcp.h>
|
|
|
|
|
#include <net/route.h>
|
|
|
|
|
#include <net/dst.h>
|
|
|
|
|
@ -17,6 +18,7 @@
|
|
|
|
|
#include <linux/spinlock.h>
|
|
|
|
|
#include <linux/netfilter_ipv4/ip_tables.h>
|
|
|
|
|
#include <linux/netfilter_ipv4.h>
|
|
|
|
|
#include <linux/netfilter_ipv6.h>
|
|
|
|
|
#include <linux/netfilter/x_tables.h>
|
|
|
|
|
#include "xt_MEDIAPROXY.h"
|
|
|
|
|
|
|
|
|
|
@ -150,7 +152,7 @@ static struct seq_operations proc_main_list_seq_ops = {
|
|
|
|
|
static struct mediaproxy_table *new_table(void) {
|
|
|
|
|
struct mediaproxy_table *t;
|
|
|
|
|
|
|
|
|
|
DBG(KERN_DEBUG "Creating new table\n");
|
|
|
|
|
DBG("Creating new table\n");
|
|
|
|
|
|
|
|
|
|
if (!try_module_get(THIS_MODULE))
|
|
|
|
|
return NULL;
|
|
|
|
|
@ -269,7 +271,7 @@ static void target_push(struct mediaproxy_target *t) {
|
|
|
|
|
if (!atomic_dec_and_test(&t->refcnt))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
DBG(KERN_DEBUG "Freeing target\n");
|
|
|
|
|
DBG("Freeing target\n");
|
|
|
|
|
|
|
|
|
|
kfree(t);
|
|
|
|
|
}
|
|
|
|
|
@ -309,7 +311,7 @@ static void table_push(struct mediaproxy_table *t) {
|
|
|
|
|
if (!atomic_dec_and_test(&t->refcnt))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
DBG(KERN_DEBUG "Freeing table\n");
|
|
|
|
|
DBG("Freeing table\n");
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
|
|
|
if (!t->target[i])
|
|
|
|
|
@ -347,7 +349,7 @@ static int unlink_table(struct mediaproxy_table *t) {
|
|
|
|
|
if (t->id >= MAX_ID)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
DBG(KERN_DEBUG "Unlinking table %u\n", t->id);
|
|
|
|
|
DBG("Unlinking table %u\n", t->id);
|
|
|
|
|
|
|
|
|
|
write_lock_irqsave(&table_lock, flags);
|
|
|
|
|
if (t->id >= MAX_ID || table[t->id] != t) {
|
|
|
|
|
@ -737,7 +739,7 @@ static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DBG(KERN_DEBUG "Creating new target\n");
|
|
|
|
|
DBG("Creating new target\n");
|
|
|
|
|
|
|
|
|
|
err = -ENOMEM;
|
|
|
|
|
g = kmalloc(sizeof(*g), GFP_KERNEL);
|
|
|
|
|
@ -970,7 +972,7 @@ static ssize_t proc_control_write(struct file *file, const char __user *buf, siz
|
|
|
|
|
|
|
|
|
|
switch (msg.cmd) {
|
|
|
|
|
case MMG_NOOP:
|
|
|
|
|
DBG(KERN_DEBUG "noop.\n");
|
|
|
|
|
DBG("noop.\n");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MMG_ADD:
|
|
|
|
|
@ -1022,7 +1024,7 @@ static int send_proxy_packet4(struct sk_buff *skb, struct mp_address *src, struc
|
|
|
|
|
ih = (void *) skb_push(skb, sizeof(*ih));
|
|
|
|
|
skb_reset_network_header(skb);
|
|
|
|
|
|
|
|
|
|
DBG(KERN_DEBUG "datalen=%u network_header=%p transport_header=%p\n", datalen, skb_network_header(skb), skb_transport_header(skb));
|
|
|
|
|
DBG("datalen=%u network_header=%p transport_header=%p\n", datalen, skb_network_header(skb), skb_transport_header(skb));
|
|
|
|
|
|
|
|
|
|
datalen += sizeof(*uh);
|
|
|
|
|
*uh = (struct udphdr) {
|
|
|
|
|
@ -1031,8 +1033,8 @@ static int send_proxy_packet4(struct sk_buff *skb, struct mp_address *src, struc
|
|
|
|
|
.len = htons(datalen),
|
|
|
|
|
};
|
|
|
|
|
*ih = (struct iphdr) {
|
|
|
|
|
.ihl = 5,
|
|
|
|
|
.version = 4,
|
|
|
|
|
.ihl = 5,
|
|
|
|
|
.tos = tos,
|
|
|
|
|
.tot_len = htons(sizeof(*ih) + datalen),
|
|
|
|
|
.ttl = 64,
|
|
|
|
|
@ -1066,6 +1068,60 @@ drop:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int send_proxy_packet6(struct sk_buff *skb, struct mp_address *src, struct mp_address *dst, unsigned char tos) {
|
|
|
|
|
struct ipv6hdr *ih;
|
|
|
|
|
struct udphdr *uh;
|
|
|
|
|
unsigned int datalen;
|
|
|
|
|
|
|
|
|
|
datalen = skb->len;
|
|
|
|
|
|
|
|
|
|
uh = (void *) skb_push(skb, sizeof(*uh));
|
|
|
|
|
skb_reset_transport_header(skb);
|
|
|
|
|
ih = (void *) skb_push(skb, sizeof(*ih));
|
|
|
|
|
skb_reset_network_header(skb);
|
|
|
|
|
|
|
|
|
|
DBG("datalen=%u network_header=%p transport_header=%p\n", datalen, skb_network_header(skb), skb_transport_header(skb));
|
|
|
|
|
|
|
|
|
|
datalen += sizeof(*uh);
|
|
|
|
|
*uh = (struct udphdr) {
|
|
|
|
|
.source = htons(src->port),
|
|
|
|
|
.dest = htons(dst->port),
|
|
|
|
|
.len = htons(datalen),
|
|
|
|
|
};
|
|
|
|
|
*ih = (struct ipv6hdr) {
|
|
|
|
|
.version = 6,
|
|
|
|
|
.priority = tos,
|
|
|
|
|
.payload_len = htons(datalen),
|
|
|
|
|
.nexthdr = IPPROTO_UDP,
|
|
|
|
|
.hop_limit = 64,
|
|
|
|
|
};
|
|
|
|
|
memcpy(&ih->saddr, src->ipv6, sizeof(ih->saddr));
|
|
|
|
|
memcpy(&ih->daddr, dst->ipv6, sizeof(ih->daddr));
|
|
|
|
|
|
|
|
|
|
skb->csum_start = skb_transport_header(skb) - skb->head;
|
|
|
|
|
skb->csum_offset = offsetof(struct udphdr, check);
|
|
|
|
|
uh->check = csum_ipv6_magic(&ih->saddr, &ih->daddr, datalen, IPPROTO_UDP, csum_partial(uh, datalen, 0));
|
|
|
|
|
if (uh->check == 0)
|
|
|
|
|
uh->check = CSUM_MANGLED_0;
|
|
|
|
|
|
|
|
|
|
skb->protocol = htons(ETH_P_IPV6);
|
|
|
|
|
if (ip6_route_me_harder(skb))
|
|
|
|
|
goto drop;
|
|
|
|
|
|
|
|
|
|
skb->ip_summed = CHECKSUM_NONE;
|
|
|
|
|
|
|
|
|
|
ip6_local_out(skb);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
drop:
|
|
|
|
|
kfree_skb(skb);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int send_proxy_packet(struct sk_buff *skb, struct mp_address *src, struct mp_address *dst, unsigned char tos) {
|
|
|
|
|
if (src->family != dst->family)
|
|
|
|
|
goto drop;
|
|
|
|
|
@ -1075,6 +1131,10 @@ static int send_proxy_packet(struct sk_buff *skb, struct mp_address *src, struct
|
|
|
|
|
return send_proxy_packet4(skb, src, dst, tos);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case AF_INET6:
|
|
|
|
|
return send_proxy_packet6(skb, src, dst, tos);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
goto drop;
|
|
|
|
|
}
|
|
|
|
|
@ -1127,17 +1187,17 @@ static unsigned int mediaproxy4(struct sk_buff *oskb, const struct xt_action_par
|
|
|
|
|
if (datalen < sizeof(*uh))
|
|
|
|
|
goto skip2;
|
|
|
|
|
datalen -= sizeof(*uh);
|
|
|
|
|
DBG(KERN_DEBUG "udp payload = %u\n", datalen);
|
|
|
|
|
DBG("udp payload = %u\n", datalen);
|
|
|
|
|
skb_trim(skb, datalen);
|
|
|
|
|
|
|
|
|
|
g = get_target(t, ntohs(uh->dest));
|
|
|
|
|
if (!g)
|
|
|
|
|
goto skip2;
|
|
|
|
|
|
|
|
|
|
DBG(KERN_DEBUG "target found, src "MIPF" -> dst "MIPF"\n", MIPP(g->target.src_addr), MIPP(g->target.dst_addr));
|
|
|
|
|
DBG("target found, src "MIPF" -> dst "MIPF"\n", MIPP(g->target.src_addr), MIPP(g->target.dst_addr));
|
|
|
|
|
|
|
|
|
|
if (g->target.mirror_addr.family) {
|
|
|
|
|
DBG(KERN_DEBUG "sending mirror packet to dst "MIPF"\n", MIPP(g->target.mirror_addr));
|
|
|
|
|
DBG("sending mirror packet to dst "MIPF"\n", MIPP(g->target.mirror_addr));
|
|
|
|
|
skb2 = skb_copy(skb, GFP_ATOMIC);
|
|
|
|
|
err = send_proxy_packet(skb2, &g->target.src_addr, &g->target.mirror_addr, g->target.tos);
|
|
|
|
|
if (err) {
|
|
|
|
|
@ -1212,17 +1272,17 @@ static unsigned int mediaproxy6(struct sk_buff *oskb, const struct xt_action_par
|
|
|
|
|
if (datalen < sizeof(*uh))
|
|
|
|
|
goto skip2;
|
|
|
|
|
datalen -= sizeof(*uh);
|
|
|
|
|
DBG(KERN_DEBUG "udp payload = %u\n", datalen);
|
|
|
|
|
DBG("udp payload = %u\n", datalen);
|
|
|
|
|
skb_trim(skb, datalen);
|
|
|
|
|
|
|
|
|
|
g = get_target(t, ntohs(uh->dest));
|
|
|
|
|
if (!g)
|
|
|
|
|
goto skip2;
|
|
|
|
|
|
|
|
|
|
DBG(KERN_DEBUG "target found, src "MIPF" -> dst "MIPF"\n", MIPP(g->target.src_addr), MIPP(g->target.dst_addr));
|
|
|
|
|
DBG("target found, src "MIPF" -> dst "MIPF"\n", MIPP(g->target.src_addr), MIPP(g->target.dst_addr));
|
|
|
|
|
|
|
|
|
|
if (is_valid_address(&g->target.mirror_addr)) {
|
|
|
|
|
DBG(KERN_DEBUG "sending mirror packet to dst "MIPF"\n", MIPP(g->target.mirror_addr));
|
|
|
|
|
DBG("sending mirror packet to dst "MIPF"\n", MIPP(g->target.mirror_addr));
|
|
|
|
|
skb2 = skb_copy(skb, GFP_ATOMIC);
|
|
|
|
|
err = send_proxy_packet(skb2, &g->target.src_addr, &g->target.mirror_addr, g->target.tos);
|
|
|
|
|
if (err) {
|
|
|
|
|
|