summaryrefslogtreecommitdiffstats
path: root/extensions/ebt_arpreply.c
blob: 32e50b4d8d97a0d801138989a024ca3942634417 (plain)
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
/* ebt_arpreply
 *
 * Authors:
 * Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
 * Bart De Schuymer <bdschuym@pandora.be>
 *
 *  August, 2003
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ether.h>
#include <getopt.h>
#include "../include/ebtables_u.h"
#include <linux/netfilter_bridge/ebt_arpreply.h>

static int mac_supplied;

#define REPLY_MAC '1'
#define REPLY_TARGET '2'
static struct option opts[] =
{
	{ "arpreply-mac" ,    required_argument, 0, REPLY_MAC    },
	{ "arpreply-target" , required_argument, 0, REPLY_TARGET },
	{ 0 }
};

static void print_help()
{
	printf(
	"arpreply target options:\n"
	" --arpreply-mac address           : source MAC of generated reply\n"
	" --arpreply-target target         : ACCEPT, DROP, RETURN or CONTINUE\n"
	"                                    (standard target is DROP)\n");
}

static void init(struct ebt_entry_target *target)
{
	struct ebt_arpreply_info *replyinfo =
	   (struct ebt_arpreply_info *)target->data;

	replyinfo->target = EBT_DROP;
	memset(replyinfo->mac, 0, ETH_ALEN);
	mac_supplied = 0;
}

#define OPT_REPLY_MAC     0x01
#define OPT_REPLY_TARGET  0x02
static int parse(int c, char **argv, int argc,
   const struct ebt_u_entry *entry, unsigned int *flags,
   struct ebt_entry_target **target)
{
	struct ebt_arpreply_info *replyinfo =
	   (struct ebt_arpreply_info *)(*target)->data;
	struct ether_addr *addr;

	switch (c) {
	case REPLY_MAC:
		ebt_check_option2(flags, OPT_REPLY_MAC);
		if (!(addr = ether_aton(optarg)))
			ebt_print_error2("Problem with specified --arpreply-mac mac");
		memcpy(replyinfo->mac, addr, ETH_ALEN);
		mac_supplied = 1;
		break;
	case REPLY_TARGET:
		ebt_check_option2(flags, OPT_REPLY_TARGET);
		if (FILL_TARGET(optarg, replyinfo->target))
			ebt_print_error2("Illegal --arpreply-target target");
		break;

	default:
		return 0;
	}
	return 1;
}

static void final_check(const struct ebt_u_entry *entry,
   const struct ebt_entry_target *target, const char *name,
   unsigned int hookmask, unsigned int time)
{
	struct ebt_arpreply_info *replyinfo =
	   (struct ebt_arpreply_info *)target->data;

	if (entry->ethproto != ETH_P_ARP || entry->invflags & EBT_IPROTO) {
		ebt_print_error("For ARP replying the protocol must be specified as ARP");
	} else if (time == 0 && mac_supplied == 0) {
		ebt_print_error("No arpreply mac supplied");
	} else if (BASE_CHAIN && replyinfo->target == EBT_RETURN) {
		ebt_print_error("--arpreply-target RETURN not allowed on base chain");
	} else {
		CLEAR_BASE_CHAIN_BIT;
		if (strcmp(name, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING))
			ebt_print_error("arpreply only allowed in PREROUTING");
	}
}

static void print(const struct ebt_u_entry *entry,
   const struct ebt_entry_target *target)
{
	struct ebt_arpreply_info *replyinfo =
	   (struct ebt_arpreply_info *)target->data;

	printf("--arpreply-mac ");
	ebt_print_mac(replyinfo->mac);
	if (replyinfo->target == EBT_DROP)
		return;
	printf(" --arpreply-target %s", TARGET_NAME(replyinfo->target));
}

static int compare(const struct ebt_entry_target *t1,
   const struct ebt_entry_target *t2)
{
	struct ebt_arpreply_info *replyinfo1 =
	   (struct ebt_arpreply_info *)t1->data;
	struct ebt_arpreply_info *replyinfo2 =
	   (struct ebt_arpreply_info *)t2->data;

	return memcmp(replyinfo1->mac, replyinfo2->mac, ETH_ALEN) == 0
		&& replyinfo1->target == replyinfo2->target;
}

static struct ebt_u_target arpreply_target =
{
	.name		= EBT_ARPREPLY_TARGET,
	.size		= sizeof(struct ebt_arpreply_info),
	.help		= print_help,
	.init		= init,
	.parse		= parse,
	.final_check	= final_check,
	.print		= print,
	.compare	= compare,
	.extra_ops	= opts,
};

void _init(void)
{
	ebt_register_target(&arpreply_target);
}