/usr/src/xtables-addons-3.0/extensions/xt_DHCPMAC.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 | /*
* "DHCPMAC" extensions for Xtables
* Copyright © Jan Engelhardt, 2008
*
* 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/ip.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/types.h>
#include <linux/udp.h>
#include <net/ip.h>
#include <linux/netfilter/x_tables.h>
#include "xt_DHCPMAC.h"
#include "compat_xtables.h"
struct dhcp_message {
uint8_t op, htype, hlen, hops;
__be32 xid;
__be16 secs, flags;
__be32 ciaddr, yiaddr, siaddr, giaddr;
char chaddr[16];
/* Omitting all unneeded fields saves runtime memory */
/* char sname[64], file[128]; */
};
static void ether_set(unsigned char *addr, const unsigned char *op,
uint8_t mask)
{
uint8_t lo_mask;
unsigned int i;
for (i = 0; i < ETH_ALEN && mask > 0; ++i) {
lo_mask = (mask >= 8) ? 8 : mask;
/* FF << 4 >> 4 = 0F */
lo_mask = (uint8_t)(~0U << lo_mask) >> lo_mask;
addr[i] &= lo_mask;
addr[i] |= op[i] & ~lo_mask;
if (mask >= 8)
mask -= 8;
else
mask = 0;
}
}
static bool ether_cmp(const unsigned char *lh, const unsigned char *rh,
uint8_t mask)
{
uint8_t lo_mask;
unsigned int i;
#define ZMAC_FMT "%02X:%02X:%02X:%02X:%02X:%02X"
#define ZMACHEX(s) s[0], s[1], s[2], s[3], s[4], s[5]
for (i = 0; i < ETH_ALEN && mask > 0; ++i) {
lo_mask = (mask >= 8) ? 8 : mask;
/* ~(0xFF << 4 >> 4) = ~0x0F = 0xF0 */
lo_mask = ~((uint8_t)(~0U << lo_mask) >> lo_mask);
if ((lh[i] ^ rh[i]) & lo_mask)
return false;
if (mask >= 8)
mask -= 8;
else
mask = 0;
}
return true;
}
static bool
dhcpmac_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct dhcpmac_info *info = par->matchinfo;
const struct dhcp_message *dh;
struct dhcp_message dhcpbuf;
dh = skb_header_pointer(skb, par->thoff + sizeof(struct udphdr),
sizeof(dhcpbuf), &dhcpbuf);
if (dh == NULL)
/*
* No hotdrop. This packet does not look like DHCP, but other
* matches may still have a valid reason to get their chance
* to match on this.
*/
return false;
return ether_cmp((const void *)dh->chaddr, info->addr, info->mask);
}
static unsigned int
dhcpmac_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct dhcpmac_info *info = par->targinfo;
struct dhcp_message dhcpbuf, *dh;
struct udphdr udpbuf, *udph;
unsigned int i;
if (!skb_make_writable(skb, 0))
return NF_DROP;
udph = skb_header_pointer(skb, ip_hdrlen(skb),
sizeof(udpbuf), &udpbuf);
if (udph == NULL)
return NF_DROP;
dh = skb_header_pointer(skb, ip_hdrlen(skb) + sizeof(udpbuf),
sizeof(dhcpbuf), &dhcpbuf);
if (dh == NULL)
return NF_DROP;
for (i = 0; i < sizeof(dh->chaddr); i += 2)
csum_replace2(&udph->check, *(const __be16 *)(dh->chaddr + i), 0);
ether_set(dh->chaddr, info->addr, info->mask);
for (i = 0; i < sizeof(dh->chaddr); i += 2)
csum_replace2(&udph->check, 0, *(const __be16 *)(dh->chaddr + i));
return XT_CONTINUE;
}
static struct xt_target dhcpmac_tg_reg __read_mostly = {
.name = "DHCPMAC",
.revision = 0,
.family = NFPROTO_IPV4,
.proto = IPPROTO_UDP,
.table = "mangle",
.target = dhcpmac_tg,
.targetsize = XT_ALIGN(sizeof(struct dhcpmac_info)),
.me = THIS_MODULE,
};
static struct xt_match dhcpmac_mt_reg __read_mostly = {
.name = "dhcpmac",
.revision = 0,
.family = NFPROTO_IPV4,
.proto = IPPROTO_UDP,
.match = dhcpmac_mt,
.matchsize = sizeof(struct dhcpmac_info),
.me = THIS_MODULE,
};
static int __init dhcpmac_init(void)
{
int ret;
ret = xt_register_target(&dhcpmac_tg_reg);
if (ret != 0)
return ret;
ret = xt_register_match(&dhcpmac_mt_reg);
if (ret != 0) {
xt_unregister_target(&dhcpmac_tg_reg);
return ret;
}
return 0;
}
static void __exit dhcpmac_exit(void)
{
xt_unregister_target(&dhcpmac_tg_reg);
xt_unregister_match(&dhcpmac_mt_reg);
}
module_init(dhcpmac_init);
module_exit(dhcpmac_exit);
MODULE_DESCRIPTION("Xtables: Clamp DHCP MAC to packet MAC addresses");
MODULE_AUTHOR("Jan Engelhardt ");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_DHCPMAC");
MODULE_ALIAS("ipt_dhcpmac");
|