This file is indexed.

/usr/src/xtables-addons-3.0/extensions/xt_length2.c is in xtables-addons-dkms 3.0-0.1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
/*
 *	xt_length - Xtables module to match packet length
 *	Copyright © Jan Engelhardt , 2007 - 2009
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License; either
 *	version 2 of the License, or any later version, as published by the
 *	Free Software Foundation.
 */
#include <linux/dccp.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/icmp.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/sctp.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include "xt_length2.h"
#include "compat_xtables.h"
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
#	define WITH_IPV6 1
#endif
#ifndef NEXTHDR_IPV4
#	define NEXTHDR_IPV4 4
#endif

MODULE_AUTHOR("Jan Engelhardt ");
MODULE_DESCRIPTION("Xtables: Packet length (Layer3,4,5) match");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_length2");
MODULE_ALIAS("ip6t_length2");

static bool
xtlength_layer5_tcp(unsigned int *length, const struct sk_buff *skb,
                    unsigned int offset)
{
	const struct tcphdr *tcph;
	struct tcphdr buf;

	tcph = skb_header_pointer(skb, offset, sizeof(buf), &buf);
	if (tcph == NULL)
		return false;

	*length = skb->len - offset;
	if (*length >= 4 * tcph->doff)
		*length -= 4 * tcph->doff;
	return true;
}

static bool
xtlength_layer5_dccp(unsigned int *length, const struct sk_buff *skb,
                     unsigned int offset)
{
	const struct dccp_hdr *dh;
	struct dccp_hdr dhbuf;

	dh = skb_header_pointer(skb, offset, sizeof(dhbuf), &dhbuf);
	if (dh == NULL)
		return false;

	*length = skb->len - offset;
	if (*length >= 4 * dh->dccph_doff)
		*length -= 4 * dh->dccph_doff;
	return true;
}

static inline bool
xtlength_layer5(unsigned int *length, const struct sk_buff *skb,
                unsigned int prot, unsigned int offset)
{
	switch (prot) {
	case IPPROTO_TCP:
		return xtlength_layer5_tcp(length, skb, offset);
	case IPPROTO_UDP:
	case IPPROTO_UDPLITE:
		*length = skb->len - offset - sizeof(struct udphdr);
		return true;
	case IPPROTO_SCTP:
		*length = skb->len - offset - sizeof(struct sctphdr);
		return true;
	case IPPROTO_DCCP:
		return xtlength_layer5_dccp(length, skb, offset);
	case IPPROTO_ICMP:
		*length = skb->len - offset - sizeof(struct icmphdr);
		return true;
	case IPPROTO_ICMPV6:
		*length = skb->len - offset -
		          offsetof(struct icmp6hdr, icmp6_dataun);
		return true;
	case IPPROTO_AH:
		*length = skb->len - offset - sizeof(struct ip_auth_hdr);
		return true;
	case IPPROTO_ESP:
		*length = skb->len - offset - sizeof(struct ip_esp_hdr);
		return true;
	}
	return false;
}

static bool
xtlength_layer7_sctp(unsigned int *length, const struct sk_buff *skb,
                     unsigned int offset)
{
	const struct sctp_chunkhdr *ch;
	struct sctp_chunkhdr chbuf;
	unsigned int pos;

	*length = 0;
	for (pos = sizeof(struct sctphdr); pos < skb->len;
	     pos += ntohs(ch->length))
	{
		ch = skb_header_pointer(skb, offset + pos,
		     sizeof(chbuf), &chbuf);
		if (ch == NULL)
			return false;
		if (ch->type != SCTP_CID_DATA)
			continue;
		*length += ntohs(ch->length);
	}
	return true;
}

static bool xtlength_layer7(unsigned int *length, const struct sk_buff *skb,
                            unsigned int proto, unsigned int offset)
{
	switch (proto) {
	case IPPROTO_SCTP:
		return xtlength_layer7_sctp(length, skb, offset);
	default:
		return xtlength_layer5(length, skb, proto, offset);
	}
}

static bool
length2_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
	const struct xt_length_mtinfo2 *info = par->matchinfo;
	const struct iphdr *iph = ip_hdr(skb);
	unsigned int len = 0;
	bool hit = true;

	if (info->flags & XT_LENGTH_LAYER3)
		len = ntohs(iph->tot_len);
	else if (info->flags & XT_LENGTH_LAYER4)
		len = ntohs(iph->tot_len) - par->thoff;
	else if (info->flags & XT_LENGTH_LAYER5)
		hit = xtlength_layer5(&len, skb, iph->protocol, par->thoff);
	else if (info->flags & XT_LENGTH_LAYER7)
		hit = xtlength_layer7(&len, skb, iph->protocol, par->thoff);
	if (!hit)
		return false;

	return (len >= info->min && len <= info->max) ^
	       !!(info->flags & XT_LENGTH_INVERT);
}

#ifdef WITH_IPV6
/**
 * llayer4_proto - figure out the L4 protocol in an IPv6 packet
 * @skb:	skb pointer
 * @offset:	position at which L4 starts (equal to 'protoff' in IPv4 code)
 * @hotdrop:	hotdrop pointer
 *
 * Searches for a recognized L4 header. On success, fills in @offset and
 * returns the protocol number. If not found, %NEXTHDR_MAX is returned.
 * On error, @hotdrop is set.
 */
static unsigned int
llayer4_proto(const struct sk_buff *skb, unsigned int *offset, bool *hotdrop)
{
	/*
	 * Do encapsulation first so that %NEXTHDR_TCP does not hit the TCP
	 * part in an IPv6-in-IPv6 encapsulation.
	 */
	static const unsigned int types[] =
		{IPPROTO_IPV6, IPPROTO_IPIP, IPPROTO_ESP, IPPROTO_AH,
		IPPROTO_ICMP, IPPROTO_TCP, IPPROTO_UDP, IPPROTO_UDPLITE,
		IPPROTO_SCTP, IPPROTO_DCCP};
	unsigned int i;
	int err;

	for (i = 0; i < ARRAY_SIZE(types); ++i) {
		err = ipv6_find_hdr(skb, offset, types[i], NULL, NULL);
		if (err >= 0)
			return types[i];
		if (err != -ENOENT) {
			*hotdrop = true;
			break;
		}
	}

	return NEXTHDR_MAX;
}

static bool
length2_mt6(const struct sk_buff *skb, struct xt_action_param *par)
{
	const struct xt_length_mtinfo2 *info = par->matchinfo;
	const struct ipv6hdr *iph = ipv6_hdr(skb);
	unsigned int len = 0, l4proto;
	/* par->thoff would only set if ip6tables -p was used; so just use 0 */
	unsigned int thoff = 0;
	bool hit = true;

	if (info->flags & XT_LENGTH_LAYER3) {
		if (iph->payload_len == 0)
			/* Jumbogram */
			len = skb->len;
		else
			len = sizeof(struct ipv6hdr) + ntohs(iph->payload_len);
	} else {
		l4proto = llayer4_proto(skb, &thoff, &par->hotdrop);
		if (l4proto == NEXTHDR_MAX)
			return false;
		if (info->flags & XT_LENGTH_LAYER4)
			len = skb->len - thoff;
		else if (info->flags & XT_LENGTH_LAYER5)
			hit = xtlength_layer5(&len, skb, l4proto, thoff);
		else if (info->flags & XT_LENGTH_LAYER7)
			hit = xtlength_layer7(&len, skb, l4proto, thoff);
	}
	if (!hit)
		return false;

	return (len >= info->min && len <= info->max) ^
	       !!(info->flags & XT_LENGTH_INVERT);
}
#endif

static struct xt_match length2_mt_reg[] __read_mostly = {
	{
		.name           = "length2",
		.revision       = 2,
		.family         = NFPROTO_IPV4,
		.match          = length2_mt,
		.matchsize      = sizeof(struct xt_length_mtinfo2),
		.me             = THIS_MODULE,
	},
#ifdef WITH_IPV6
	{
		.name           = "length2",
		.revision       = 2,
		.family         = NFPROTO_IPV6,
		.match          = length2_mt6,
		.matchsize      = sizeof(struct xt_length_mtinfo2),
		.me             = THIS_MODULE,
	},
#endif
};

static int __init length2_mt_init(void)
{
	return xt_register_matches(length2_mt_reg, ARRAY_SIZE(length2_mt_reg));
}

static void __exit length2_mt_exit(void)
{
	xt_unregister_matches(length2_mt_reg, ARRAY_SIZE(length2_mt_reg));
}

module_init(length2_mt_init);
module_exit(length2_mt_exit);