From 544bce95606fa816af414a43a3b01dd7b6abc717 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Tue, 10 Jun 2014 03:06:32 +0200 Subject: [PATCH] Add basic RTP support (fix #13) Can be configured with the new --format option: - auto: strip RTP if detected (default) - rtp: require RTP - raw: require no RTP No padded, extended or mixed RTP support yet. --- iptables-module/libxt_mpeg2ts.c | 47 ++++++++++++++++++++++++--- iptables-module/xt_mpeg2ts.c | 57 ++++++++++++++++++++++----------- iptables-module/xt_mpeg2ts.h | 8 +++-- 3 files changed, 87 insertions(+), 25 deletions(-) diff --git a/iptables-module/libxt_mpeg2ts.c b/iptables-module/libxt_mpeg2ts.c index e325c35..9aa9d00 100644 --- a/iptables-module/libxt_mpeg2ts.c +++ b/iptables-module/libxt_mpeg2ts.c @@ -42,12 +42,14 @@ drop detection stats can be disabled via inverting the parameter --drop-detect, eg. "! --drop-detect". + Setting the --format parameter to rtp or raw demands a certain format. */ static const struct option mpeg2ts_mt_opts[] = { {.name = "name", .has_arg = true, .val = 'n'}, {.name = "drop-detect", .has_arg = false, .val = 'd'}, {.name = "match-drop", .has_arg = false, .val = 'm'}, {.name = "max-streams", .has_arg = true, .val = 'x'}, + {.name = "format", .has_arg = true, .val = 'f'}, {NULL}, }; @@ -56,10 +58,11 @@ static void mpeg2ts_mt_help(void) printf( "mpeg2ts (MPEG2 Transport Stream) match options:\n" "VERSION %s\n" -" [--name ] Name for proc file /proc/net/xt_mpeg2ts/rule_NAME\n" -" [--match-drop] Match on lost TS frames (default: off)\n" -" [--drop-detect] Detect TS frame loss and store stats (default: ON)\n" -" [--max-streams ] Track 'max' number of streams (per rule)\n", +" [--name ] Name for proc file /proc/net/xt_mpeg2ts/rule_NAME\n" +" [--match-drop] Match on lost TS frames (default: off)\n" +" [--drop-detect] Detect TS frame loss and store stats (default: ON)\n" +" [--max-streams ] Track 'max' number of streams (per rule)\n" +" [--format {auto|rtp|raw} Encapsulation format (default: auto)\n", version ); } @@ -72,6 +75,9 @@ static void mpeg2ts_mt_init(struct xt_entry_match *match) /* Match on drops is disabled per default */ /* XT_MPEG2TS_MATCH_DROP */ + + /* Auto-detect format */ + info->flags |= XT_MPEG2TS_FORMAT_AUTO; } static int mpeg2ts_mt_parse(int c, char **argv, int invert, unsigned int *flags, @@ -156,6 +162,22 @@ static int mpeg2ts_mt_parse(int c, char **argv, int invert, unsigned int *flags, break; + case 'f': /* --format */ + if (*flags & XT_MPEG2TS_FORMAT) + xtables_error(PARAMETER_PROBLEM, + "Can't specify --format option twice"); + *flags |= XT_MPEG2TS_FORMAT; + + if (strcmp(optarg, "auto") == 0) + info->flags = (info->flags & ~XT_MPEG2TS_FORMAT) | XT_MPEG2TS_FORMAT_AUTO; + else if (strcmp(optarg, "rtp") == 0) + info->flags = (info->flags & ~XT_MPEG2TS_FORMAT) | XT_MPEG2TS_FORMAT_RTP; + else if (strcmp(optarg, "raw") == 0) + info->flags = (info->flags & ~XT_MPEG2TS_FORMAT) | XT_MPEG2TS_FORMAT_RAW; + else + xtables_error(PARAMETER_PROBLEM, "bad --format argument: `%s'", optarg); + break; + default: return false; } @@ -182,6 +204,15 @@ static void mpeg2ts_mt_print(const void *entry, if (info->flags & XT_MPEG2TS_MAX_STREAMS) printf(" max-streams:%u", info->cfg.max); + + switch (info->flags & XT_MPEG2TS_FORMAT) { + case XT_MPEG2TS_FORMAT_RTP: + printf(" format:rtp"); + break; + case XT_MPEG2TS_FORMAT_RAW: + printf(" format:raw"); + break; + } } static void mpeg2ts_mt_save(const void *entry, @@ -202,6 +233,14 @@ static void mpeg2ts_mt_save(const void *entry, if (info->flags & XT_MPEG2TS_MAX_STREAMS) printf(" --max-streams %u", info->cfg.max); + switch (info->flags & XT_MPEG2TS_FORMAT) { + case XT_MPEG2TS_FORMAT_RTP: + printf(" --format rtp"); + break; + case XT_MPEG2TS_FORMAT_RAW: + printf(" --format raw"); + break; + } } static struct xtables_match mpeg2ts_mt_reg = { diff --git a/iptables-module/xt_mpeg2ts.c b/iptables-module/xt_mpeg2ts.c index 91ae4a0..c498ffd 100644 --- a/iptables-module/xt_mpeg2ts.c +++ b/iptables-module/xt_mpeg2ts.c @@ -1122,6 +1122,14 @@ is_mpeg2ts_packet(const unsigned char *payload_ptr, uint16_t payload_len) } +static uint16_t +get_rtp_header_length(const unsigned char *payload_ptr, uint16_t payload_len) +{ + /* currently, only non-padded, non-extended, non-mixed RTP is supported */ + return *payload_ptr == 0x80 ? 12 : 0; +} + + static bool xt_mpeg2ts_match(const struct sk_buff *skb, struct xt_action_param *par) { @@ -1131,7 +1139,9 @@ xt_mpeg2ts_match(const struct sk_buff *skb, struct xt_action_param *par) struct udphdr _udph; __be32 saddr, daddr; uint16_t ulen; - uint16_t hdr_size; + uint16_t format; + uint16_t udp_hdr_size; + uint16_t rtp_hdr_size; uint16_t payload_len; const unsigned char *payload_ptr; @@ -1187,18 +1197,18 @@ xt_mpeg2ts_match(const struct sk_buff *skb, struct xt_action_param *par) ulen = ntohs(uh->len); /* How much do we need to skip to access payload data */ - hdr_size = par->thoff + sizeof(struct udphdr); - payload_ptr = skb_network_header(skb) + hdr_size; - /* payload_ptr = skb->data + hdr_size; */ - BUG_ON(payload_ptr != (skb->data + hdr_size)); + udp_hdr_size = par->thoff + sizeof(struct udphdr); + payload_ptr = skb_network_header(skb) + udp_hdr_size; + /* payload_ptr = skb->data + udp_hdr_size; */ + BUG_ON(payload_ptr != (skb->data + udp_hdr_size)); /* Different ways to determine the payload_len. Think the * safest is to use the skb->len, as we really cannot trust * the contents of the packet. - payload_len = ntohs(iph->tot_len)- hdr_size; + payload_len = ntohs(iph->tot_len)- udp_hdr_size; payload_len = ulen - sizeof(struct udphdr); */ - payload_len = skb->len - hdr_size; + payload_len = skb->len - udp_hdr_size; /* Not sure if we need to clone packets if (skb_shared(skb)) @@ -1208,23 +1218,32 @@ xt_mpeg2ts_match(const struct sk_buff *skb, struct xt_action_param *par) msg_dbg(RX_STATUS, "skb(0x%p) NOT cloned", skb); */ - if (is_mpeg2ts_packet(payload_ptr, payload_len)) { - msg_dbg(PKTDATA, "Jubii - its a MPEG2TS packet"); - - if (!(info->flags & XT_MPEG2TS_DETECT_DROP)) { - /* ! --drop-detect */ - /* Don't perform drop detection, just match mpeg2ts */ - res = true; + format = info->flags & XT_MPEG2TS_FORMAT; + if (format == XT_MPEG2TS_FORMAT_AUTO || format == XT_MPEG2TS_FORMAT_RTP) { + rtp_hdr_size = get_rtp_header_length(payload_ptr, payload_len); + if (!rtp_hdr_size) { + if (format == XT_MPEG2TS_FORMAT_RTP) + return false; } else { - skips = dissect_mpeg2ts(payload_ptr, payload_len, - skb, uh, info); + payload_ptr += rtp_hdr_size; + payload_len -= rtp_hdr_size; } - } else { - msg_dbg(PKTDATA, "Not a MPEG2 TS packet " - "(pkt from:%pI4 to:%pI4)", &saddr, &daddr); + } + if (!is_mpeg2ts_packet(payload_ptr, payload_len)) { return false; } + msg_dbg(PKTDATA, "Jubii - its a MPEG2TS packet"); + + if (!(info->flags & XT_MPEG2TS_DETECT_DROP)) { + /* ! --drop-detect */ + /* Don't perform drop detection, just match mpeg2ts */ + res = true; + } else { + skips = dissect_mpeg2ts(payload_ptr, payload_len, + skb, uh, info); + } + if (info->flags & XT_MPEG2TS_MATCH_DROP) res = !!(skips); /* Convert to a bool */ diff --git a/iptables-module/xt_mpeg2ts.h b/iptables-module/xt_mpeg2ts.h index 941ee2d..22fc425 100644 --- a/iptables-module/xt_mpeg2ts.h +++ b/iptables-module/xt_mpeg2ts.h @@ -32,10 +32,14 @@ enum { XT_MPEG2TS_MAX_STREAMS = 1 << 1, XT_MPEG2TS_PARAM_NAME = 1 << 2, XT_MPEG2TS_MATCH_DROP = 1 << 3, - /*Future:*/ - XT_MPEG2TS_RECORD_COUNTERS = 1 << 4, + XT_MPEG2TS_RECORD_COUNTERS = 1 << 4, /* Future */ + XT_MPEG2TS_FORMAT = 3 << 5, + XT_MPEG2TS_FORMAT_AUTO = 0 << 5, + XT_MPEG2TS_FORMAT_RTP = 1 << 5, + XT_MPEG2TS_FORMAT_RAW = 2 << 5, }; + /* Details of this hash structure is hidden in kernel space xt_mpeg2ts.c */ struct xt_rule_mpeg2ts_conn_htable;