├── .github └── workflows │ └── c-compile.yml ├── README.md └── nat46 ├── Makefile ├── README.md ├── files └── etc │ └── modules.d │ └── 33-nat46 └── modules ├── Makefile ├── README ├── nat46-core.c ├── nat46-core.h ├── nat46-glue.c ├── nat46-glue.h ├── nat46-module.c ├── nat46-module.h ├── nat46-netdev.c └── nat46-netdev.h /.github/workflows/c-compile.yml: -------------------------------------------------------------------------------- 1 | on: 2 | - push 3 | - pull_request 4 | - workflow_dispatch 5 | 6 | name: C/C++ CI prototype 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: build the NAT46 module 14 | run: | 15 | cd nat46/modules 16 | KCPPFLAGS='-DNAT46_VERSION=\"test\" -Werror' make 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | nat46 2 | ===== 3 | 4 | This is an OpenWRT feed with a Linux kernel module implementing flexible NAT46. 5 | 6 | Compiling 7 | ========= 8 | 9 | With Barrier Breaker (trunk), add the following line to *feeds.conf.default*: 10 | ``` 11 | src-git nat46 https://github.com/ayourtch/nat46.git 12 | ``` 13 | 14 | then issue: 15 | 16 | ``` 17 | ./scripts/feeds update -a 18 | ./scripts/feeds install -a -p nat46 19 | ``` 20 | 21 | This will cause the following to appear in the "make menuconfig": 22 | 23 | * Kernel modules -> Network Support -> kmod-nat46 24 | 25 | Managing 26 | ======== 27 | 28 | The management of the NAT46 interfaces is done via the /proc/net/nat46/control file. 29 | 30 | For more information about the module, take a look at the nat46/modules/README file. 31 | 32 | 33 | -------------------------------------------------------------------------------- /nat46/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2006-2012 OpenWrt.org 3 | # 4 | # This is free software, licensed under the GNU General Public License v2. 5 | # See /LICENSE for more information. 6 | # 7 | 8 | include $(TOPDIR)/rules.mk 9 | include $(INCLUDE_DIR)/kernel.mk 10 | 11 | PKG_NAME:=nat46 12 | PKG_VERSION:=0000000 13 | 14 | include $(INCLUDE_DIR)/package.mk 15 | 16 | define KernelPackage/nat46 17 | DEPENDS:=+kmod-ipv6 18 | TITLE:=Stateless NAT46 translation kernel module 19 | SECTION:=kernel 20 | SUBMENU:=Network Support 21 | FILES:=$(PKG_BUILD_DIR)/modules/nat46.ko 22 | endef 23 | 24 | 25 | define Build/Prepare 26 | $(call Build/Prepare/Default) 27 | $(CP) -r ./* $(PKG_BUILD_DIR)/ 28 | endef 29 | 30 | 31 | MAKE_KMOD := $(MAKE) -C "$(LINUX_DIR)" \ 32 | CROSS_COMPILE="$(TARGET_CROSS)" \ 33 | ARCH="$(LINUX_KARCH)" \ 34 | PATH="$(TARGET_PATH)" \ 35 | SUBDIRS="$(PKG_BUILD_DIR)/kmod" \ 36 | 37 | define Build/Compile 38 | # Compile the kernel part 39 | $(MAKE_KMOD) \ 40 | SUBDIRS="$(PKG_BUILD_DIR)/modules" \ 41 | MODFLAGS="-DMODULE -mlong-calls" \ 42 | modules 43 | pwd 44 | endef 45 | 46 | define KernelPackage/nat46/install 47 | $(CP) -r ./files/* $(1)/ 48 | endef 49 | 50 | $(eval $(call KernelPackage,nat46)) 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /nat46/README.md: -------------------------------------------------------------------------------- 1 | See README in modules/ 2 | 3 | -------------------------------------------------------------------------------- /nat46/files/etc/modules.d/33-nat46: -------------------------------------------------------------------------------- 1 | nat46 2 | 3 | -------------------------------------------------------------------------------- /nat46/modules/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += nat46.o 2 | nat46-objs := nat46-netdev.o nat46-module.o nat46-core.o nat46-glue.o 3 | CFLAGS_nat46.o := -DDEBUG 4 | 5 | EXTRA_CFLAGS += -Wno-date-time 6 | 7 | all: 8 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 9 | 10 | clean: 11 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 12 | -------------------------------------------------------------------------------- /nat46/modules/README: -------------------------------------------------------------------------------- 1 | ABOUT AND USAGE 2 | --------------- 3 | 4 | This is a generic stateless NAT46 kernel module for Linux. 5 | 6 | It supports multiple simultaneous instances of NAT46 on the same host, 7 | allowing to implement sophisticated translation strategies just 8 | by using routing to direct the packets to the appropriate interface. 9 | 10 | Upon loading, it creates a file /proc/net/nat46/control, which is used 11 | to interact with it. 12 | 13 | echo add | sudo tee /proc/net/nat46/control 14 | create a new nat46 interface with a specified name 15 | 16 | echo del | sudo tee /proc/net/nat46/control 17 | delete the existing nat46 interface with a specified name 18 | 19 | echo config | sudo tee /proc/net/nat46/control 20 | pass the data to configuration routine of 21 | the respective nat46 interface. In case multiple rules are 22 | present - this command controls the very last one in the ruleset. 23 | 24 | echo insert | sudo tee /proc/net/nat46/control 25 | insert a new rule with the specified config string at the head 26 | of the rule set for the device. 27 | 28 | echo remove | sudo tee /proc/net/nat46/control 29 | removes a rule with the specified config string from the 30 | rule set for the device. 31 | 32 | CONFIGURING NAT46 DEVICE 33 | ----------------------- 34 | 35 | Configuration parameters for the device take form of "name value" pairs, 36 | with the following values: 37 | 38 | debug 39 | set the debug level on the device to 40 | 41 | local. 42 | set the local side translation rule's parameter to 43 | 44 | remote. 45 | set the remote side tranlation rule's parameter to 46 | 47 | 48 | The rules for local and remote addresses are using the same mechanism for translation 49 | for greater flexibility and allow several arguments. The most important argument is 50 | "style", which determines what kind of the translation mechanism is employed for 51 | this rule: 52 | 53 | .style NONE 54 | this is a very simplistic style: it always fails, unless you configure 55 | a /32 IPv4 prefix and a /128 IPv6 prefix - at which point it starts to 56 | function as a single 1:1 translation rule. 57 | 58 | .v4 /32 59 | .v6 /128 60 | both of these parameters must be set for this translation style 61 | to function properly. They define the two addresses for 62 | the 1:1 mapping. 63 | 64 | .ea-len 65 | .psid-offset 66 | .fmr-flag 67 | ignored in this translation style 68 | 69 | NB: in the future this translation mechanism may be extended to allow 1:1 70 | subnet mapping. 71 | 72 | .style RFC6052 73 | this is a rule which allows to implement the mapping used in NAT64 74 | environments to represent the entire IPv4 internet as an IPv6 prefix. 75 | 76 | .v6 / 77 | this defines IPv6 prefix length to translate the IPv4 internet into. 78 | The allowed prefix lengths are 32, 40, 48, 56, 64, 96. 79 | If a disallowed length is used, the translation fails. 80 | 81 | .v4 / 82 | this parameter is ignored for now in this translation style. 83 | For backwards compatibility it should be 0.0.0.0/0 84 | 85 | .ea-len 86 | .psid-offset 87 | .fmr-flag 88 | ignored in this translation style 89 | 90 | .style MAP 91 | this is a translation rule for the MAP (Mapping Address and Port) algorithm, 92 | which may include the layer 4 identifier (tcp/udp port or ICMP id). 93 | 94 | .v6 / 95 | this parameter defines the MAP domain IPv6 prefix 96 | 97 | .v4 / 98 | this parameter defines the MAP domain IPv4 prefix 99 | 100 | .ea-len 101 | this parameter defines the length of the embedded address bits 102 | within the IPv6 prefix that has been allocated. 103 | 104 | .psid-offset 105 | this parameter specifies how many bits to the right to shift 106 | the bits of the psid within the port value. 107 | 108 | .fmr-flag 109 | this parameter allows the "local" rule to be tried as a "remote" rule 110 | as well. In MAP terminology, this allows to implement FMR rule by just 111 | setting this flag. This flag is used only on the "local" side, and is 112 | ignored for the "remote" side. 113 | 114 | 115 | CODE STRUCTURE 116 | -------------- 117 | 118 | There are several groups of files: 119 | 120 | nat46-module.* 121 | These files deal with the overall Linux module handling: loading / unloading, 122 | creating and destroying the /proc control file, as well as parsing the commands 123 | to pass on to the netdev portion of the code. 124 | 125 | nat46-netdev.* 126 | Network device management code. This module accepts the high-level commands and 127 | performs the device-level work: locating the devices in the chain, grouping 128 | the functions into the device structures, etc. This module adds the pointers 129 | the processing functions which are defined in the core group. 130 | 131 | nat46-core.* 132 | Core processing routines. These do not do any netdevice/module work, they use 133 | primarily sk_buff and nat64_instance_t data structures in order to operate. 134 | They use the Linux kernel and glue functions. 135 | 136 | nat46-glue.* 137 | These are the "adaptation" functions, over time it is expected there will 138 | be almost nothing. The reason for the "glue" code to exist is to share 139 | the core code with userland implementations. 140 | 141 | 142 | ACKNOWLEDGEMENTS 143 | ---------------- 144 | 145 | This code has been inspired or uses some parts of the following: 146 | 147 | * CERNET MAP implementation 148 | 149 | https://github.com/cernet/MAP 150 | 151 | * Stateful NAT64 kernel module implementation by Julius Kriukas 152 | 153 | https://github.com/fln/nat64 154 | 155 | * Stateless NAT46 kernel module implementation by Tomasz Mrugalski 156 | 157 | https://github.com/tomaszmrugalski/ip46nat 158 | 159 | 160 | -------------------------------------------------------------------------------- /nat46/modules/nat46-core.c: -------------------------------------------------------------------------------- 1 | /* 2 | * core nat46 functionality. 3 | * It does not know about network devices, modules or anything similar: 4 | * those are abstracted away by other layers. 5 | * 6 | * Copyright (c) 2013-2014 Andrew Yourtchenko 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License version 2 10 | * as published by the Free Software Foundation 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | */ 18 | 19 | #include 20 | #include 21 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0) 22 | #include 23 | #else 24 | #include 25 | #endif 26 | #if IS_ENABLED(CONFIG_NF_CONNTRACK) 27 | #include 28 | #endif 29 | #include 30 | #include 31 | 32 | #include "nat46-glue.h" 33 | #include "nat46-core.h" 34 | #include "nat46-module.h" 35 | 36 | static void 37 | nat46debug_dump(nat46_instance_t *nat46, int level, void *addr, int len) 38 | { 39 | char tohex[] = "0123456789ABCDEF"; 40 | int i = 0; 41 | int k = 0; 42 | unsigned char *pc = addr; 43 | 44 | char buf0[32]; // offset 45 | char buf1[64]; // hex 46 | char buf2[64]; // literal 47 | 48 | char *pc1 = buf1; 49 | char *pc2 = buf2; 50 | 51 | while(--len >= 0) { 52 | if(i % 16 == 0) { 53 | for(k=0; k<9; k++) { 54 | buf0[k] = 0; 55 | } 56 | for(k=0; k<8; k++) { 57 | buf0[7-k] = tohex[ 0xf & (i >> k) ]; 58 | } 59 | buf0[8] = 0; 60 | buf1[0] = 0; 61 | buf2[0] = 0; 62 | pc1 = buf1; 63 | pc2 = buf2; 64 | } 65 | *pc1++ = tohex[*pc >> 4]; 66 | *pc1++ = tohex[*pc & 15]; 67 | *pc1++ = ' '; 68 | 69 | if(*pc >= 32 && *pc < 127) { 70 | *pc2++ = *pc; 71 | } else { 72 | *pc2++ = '.'; 73 | } 74 | i++; 75 | pc++; 76 | if(i % 16 == 0) { 77 | *pc1 = 0; 78 | *pc2 = 0; 79 | nat46debug(level, "%s: %s %s", buf0, buf1, buf2); 80 | } 81 | 82 | } 83 | if(i % 16 != 0) { 84 | while(i % 16 != 0) { 85 | *pc1++ = ' '; 86 | *pc1++ = ' '; 87 | *pc1++ = ' '; 88 | *pc2++ = ' '; 89 | i++; 90 | } 91 | *pc1 = 0; 92 | *pc2 = 0; 93 | nat46debug(level, "%s: %s %s", buf0, buf1, buf2); 94 | } 95 | } 96 | 97 | /* return the current arg, and advance the tail to the next space-separated word */ 98 | char *get_next_arg(char **ptail) { 99 | char *pc = NULL; 100 | while ((*ptail) && (**ptail) && ((**ptail == ' ') || (**ptail == '\n'))) { 101 | **ptail = 0; 102 | (*ptail)++; 103 | } 104 | pc = *ptail; 105 | 106 | while ((*ptail) && (**ptail) && ((**ptail != ' ') && (**ptail != '\n'))) { 107 | (*ptail)++; 108 | } 109 | 110 | while ((*ptail) && (**ptail) && ((**ptail == ' ') || (**ptail == '\n'))) { 111 | **ptail = 0; 112 | (*ptail)++; 113 | } 114 | 115 | if ((pc) && (0 == *pc)) { 116 | pc = NULL; 117 | } 118 | return pc; 119 | } 120 | 121 | /* 122 | * Parse an IPv6 address (if pref_len is NULL), or prefix (if it isn't). 123 | * parses destructively (places \0 between address and prefix len) 124 | */ 125 | static int try_parse_ipv6_prefix(struct in6_addr *pref, int *pref_len, char *arg) { 126 | int err = 0; 127 | char *arg_plen = strchr(arg, '/'); 128 | if (arg_plen) { 129 | *arg_plen++ = 0; 130 | if (pref_len) { 131 | *pref_len = simple_strtol(arg_plen, NULL, 10); 132 | } 133 | } 134 | err = (1 != in6_pton(arg, -1, (u8 *)pref, '\0', NULL)); 135 | return err; 136 | } 137 | 138 | static int try_parse_ipv4_prefix(u32 *v4addr, int *pref_len, char *arg) { 139 | int err = 0; 140 | char *arg_plen = strchr(arg, '/'); 141 | if (arg_plen) { 142 | *arg_plen++ = 0; 143 | if (pref_len) { 144 | *pref_len = simple_strtol(arg_plen, NULL, 10); 145 | } 146 | } 147 | err = (1 != in4_pton(arg, -1, (u8 *)v4addr, '/', NULL)); 148 | return err; 149 | } 150 | 151 | 152 | /* 153 | * parse a rule argument and put config into a rule. 154 | * advance the tail to prepare for the next arg parsing. 155 | * destructive. 156 | */ 157 | 158 | static int try_parse_rule_arg(nat46_xlate_rule_t *rule, char *arg_name, char **ptail) { 159 | int err = 0; 160 | char *val = get_next_arg(ptail); 161 | if (NULL == val) { 162 | err = -1; 163 | } else if (0 == strcmp(arg_name, "v6")) { 164 | err = try_parse_ipv6_prefix(&rule->v6_pref, &rule->v6_pref_len, val); 165 | } else if (0 == strcmp(arg_name, "v4")) { 166 | err = try_parse_ipv4_prefix(&rule->v4_pref, &rule->v4_pref_len, val); 167 | } else if (0 == strcmp(arg_name, "ea-len")) { 168 | rule->ea_len = simple_strtol(val, NULL, 10); 169 | } else if (0 == strcmp(arg_name, "psid-offset")) { 170 | rule->psid_offset = simple_strtol(val, NULL, 10); 171 | } else if (0 == strcmp(arg_name, "style")) { 172 | if (0 == strcmp("MAP", val)) { 173 | rule->style = NAT46_XLATE_MAP; 174 | } else if (0 == strcmp("MAP0", val)) { 175 | rule->style = NAT46_XLATE_MAP0; 176 | } else if (0 == strcmp("RFC6052", val)) { 177 | rule->style = NAT46_XLATE_RFC6052; 178 | } else if (0 == strcmp("NONE", val)) { 179 | rule->style = NAT46_XLATE_NONE; 180 | } else { 181 | err = 1; 182 | } 183 | } 184 | return err; 185 | } 186 | 187 | /* 188 | * Parse the config commands in the buffer, 189 | * destructive (puts zero between the args) 190 | */ 191 | 192 | int nat46_set_ipair_config(nat46_instance_t *nat46, int ipair, char *buf, int count) { 193 | char *tail = buf; 194 | char *arg_name; 195 | int err = 0; 196 | char *val; 197 | nat46_xlate_rulepair_t *apair = NULL; 198 | 199 | if ((ipair < 0) || (ipair >= nat46->npairs)) { 200 | return -1; 201 | } 202 | 203 | apair = &nat46->pairs[ipair]; 204 | 205 | while ((0 == err) && (NULL != (arg_name = get_next_arg(&tail)))) { 206 | if (0 == strcmp(arg_name, "debug")) { 207 | val = get_next_arg(&tail); 208 | if (val) { 209 | nat46->debug = simple_strtol(val, NULL, 10); 210 | } 211 | } else if (arg_name == strstr(arg_name, "local.")) { 212 | arg_name += strlen("local."); 213 | nat46debug(13, "Setting local xlate parameter"); 214 | err = try_parse_rule_arg(&apair->local, arg_name, &tail); 215 | } else if (arg_name == strstr(arg_name, "remote.")) { 216 | arg_name += strlen("remote."); 217 | nat46debug(13, "Setting remote xlate parameter"); 218 | err = try_parse_rule_arg(&apair->remote, arg_name, &tail); 219 | } 220 | } 221 | return err; 222 | } 223 | 224 | int nat46_set_config(nat46_instance_t *nat46, char *buf, int count) { 225 | int ret = -1; 226 | if (nat46->npairs > 0) { 227 | ret = nat46_set_ipair_config(nat46, nat46->npairs-1, buf, count); 228 | } 229 | return ret; 230 | } 231 | 232 | static char *xlate_style_to_string(nat46_xlate_style_t style) { 233 | switch(style) { 234 | case NAT46_XLATE_NONE: 235 | return "NONE"; 236 | case NAT46_XLATE_MAP: 237 | return "MAP"; 238 | case NAT46_XLATE_MAP0: 239 | return "MAP0"; 240 | case NAT46_XLATE_RFC6052: 241 | return "RFC6052"; 242 | } 243 | return "unknown"; 244 | } 245 | 246 | /* 247 | * Get the nat46 configuration into a supplied buffer (if non-null). 248 | */ 249 | int nat46_get_ipair_config(nat46_instance_t *nat46, int ipair, char *buf, int count) { 250 | int ret = 0; 251 | nat46_xlate_rulepair_t *apair = NULL; 252 | char *format = "local.v4 %pI4/%d local.v6 %pI6c/%d local.style %s local.ea-len %d local.psid-offset %d remote.v4 %pI4/%d remote.v6 %pI6c/%d remote.style %s remote.ea-len %d remote.psid-offset %d debug %d"; 253 | 254 | if ((ipair < 0) || (ipair >= nat46->npairs)) { 255 | return ret; 256 | } 257 | apair = &nat46->pairs[ipair]; 258 | 259 | ret = snprintf(buf, count, format, 260 | &apair->local.v4_pref, apair->local.v4_pref_len, 261 | &apair->local.v6_pref, apair->local.v6_pref_len, 262 | xlate_style_to_string(apair->local.style), 263 | apair->local.ea_len, apair->local.psid_offset, 264 | 265 | &apair->remote.v4_pref, apair->remote.v4_pref_len, 266 | &apair->remote.v6_pref, apair->remote.v6_pref_len, 267 | xlate_style_to_string(apair->remote.style), 268 | apair->remote.ea_len, apair->remote.psid_offset, 269 | 270 | nat46->debug); 271 | return ret; 272 | } 273 | 274 | int nat46_get_config(nat46_instance_t *nat46, char *buf, int count) { 275 | int ret = 0; 276 | if (nat46->npairs > 0) { 277 | ret = nat46_get_ipair_config(nat46, nat46->npairs-1, buf, count); 278 | } else { 279 | nat46debug(0, "nat46_get_config: npairs is 0"); 280 | } 281 | return ret; 282 | } 283 | 284 | /* 285 | * Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero 286 | * value if 'skb' is freed. 287 | */ 288 | static int try_reassembly(struct sk_buff *old_skb) { 289 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0) 290 | u16 zone_id = NF_CT_DEFAULT_ZONE_ID; 291 | #else 292 | u16 zone_id = NF_CT_DEFAULT_ZONE; 293 | #endif 294 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) 295 | struct net *net = dev_net(old_skb->dev); 296 | #else 297 | struct sk_buff *reasm; 298 | #endif 299 | int err; 300 | 301 | #if IS_ENABLED(CONFIG_NF_CONNTRACK) 302 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0) 303 | if (skb_nfct(old_skb)) { 304 | #else 305 | if (old_skb->nfct) { 306 | #endif 307 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0) 308 | enum ip_conntrack_info ctinfo; 309 | const struct nf_conn *ct = nf_ct_get(old_skb, &ctinfo); 310 | 311 | zone_id = nf_ct_zone_id(nf_ct_zone(ct), CTINFO2DIR(ctinfo)); 312 | #else 313 | zone_id = nf_ct_zone((struct nf_conn *)old_skb->nfct); 314 | #endif 315 | } 316 | #endif 317 | 318 | if (old_skb->protocol == htons(ETH_P_IP)) { 319 | enum ip_defrag_users user = IP_DEFRAG_CONNTRACK_IN + zone_id; 320 | 321 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) 322 | err = ip_defrag(net, old_skb, user); 323 | #else 324 | err = ip_defrag(old_skb, user); 325 | #endif 326 | if (err) { 327 | return err; 328 | } 329 | 330 | old_skb->ignore_df = 1; 331 | } else if (old_skb->protocol == htons(ETH_P_IPV6)) { 332 | enum ip6_defrag_users user = IP6_DEFRAG_CONNTRACK_IN + zone_id; 333 | 334 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) 335 | err = nf_ct_frag6_gather(net, old_skb, user); 336 | if (err) { 337 | if (err != -EINPROGRESS) { 338 | dev_kfree_skb_any(old_skb); 339 | } 340 | return err; 341 | } 342 | #else 343 | reasm = nf_ct_frag6_gather(old_skb, user); 344 | if (!reasm) { 345 | return -EINPROGRESS; 346 | } 347 | 348 | if (old_skb == reasm) { 349 | dev_kfree_skb_any(old_skb); 350 | return -EINVAL; 351 | } 352 | 353 | skb_get(old_skb); 354 | nf_ct_frag6_consume_orig(reasm); 355 | 356 | skb_morph(old_skb, reasm); 357 | old_skb->next = reasm->next; 358 | dev_consume_skb_any(reasm); 359 | #endif 360 | } else { 361 | dev_kfree_skb_any(old_skb); 362 | return -EPFNOSUPPORT; 363 | } 364 | 365 | return 0; 366 | } 367 | 368 | 369 | /******************************************************************** 370 | 371 | From RFC6052, section 2.2: 372 | 373 | +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 374 | |PL| 0-------------32--40--48--56--64--72--80--88--96--104---------| 375 | +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 376 | |32| prefix |v4(32) | u | suffix | 377 | +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 378 | |40| prefix |v4(24) | u |(8)| suffix | 379 | +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 380 | |48| prefix |v4(16) | u | (16) | suffix | 381 | +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 382 | |56| prefix |(8)| u | v4(24) | suffix | 383 | +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 384 | |64| prefix | u | v4(32) | suffix | 385 | +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 386 | |96| prefix | v4(32) | 387 | +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 388 | 389 | ********************************************************************/ 390 | 391 | static void xlate_v4_to_nat64(nat46_instance_t *nat46, nat46_xlate_rule_t *rule, void *pipv4, void *pipv6) { 392 | char *ipv4 = pipv4; 393 | char *ipv6 = pipv6; 394 | 395 | /* 'u' byte and suffix are zero */ 396 | memset(&ipv6[8], 0, 8); 397 | switch(rule->v6_pref_len) { 398 | case 32: 399 | memcpy(ipv6, &rule->v6_pref, 4); 400 | memcpy(&ipv6[4], ipv4, 4); 401 | break; 402 | case 40: 403 | memcpy(ipv6, &rule->v6_pref, 5); 404 | memcpy(&ipv6[5], ipv4, 3); 405 | ipv6[9] = ipv4[3]; 406 | break; 407 | case 48: 408 | memcpy(ipv6, &rule->v6_pref, 6); 409 | ipv6[6] = ipv4[0]; 410 | ipv6[7] = ipv4[1]; 411 | ipv6[9] = ipv4[2]; 412 | ipv6[10] = ipv4[3]; 413 | break; 414 | case 56: 415 | memcpy(ipv6, &rule->v6_pref, 7); 416 | ipv6[7] = ipv4[0]; 417 | ipv6[9] = ipv4[1]; 418 | ipv6[10] = ipv4[2]; 419 | ipv6[11] = ipv4[3]; 420 | break; 421 | case 64: 422 | memcpy(ipv6, &rule->v6_pref, 8); 423 | memcpy(&ipv6[9], ipv4, 4); 424 | break; 425 | case 96: 426 | memcpy(ipv6, &rule->v6_pref, 12); 427 | memcpy(&ipv6[12], ipv4, 4); 428 | break; 429 | } 430 | } 431 | 432 | static int xlate_nat64_to_v4(nat46_instance_t *nat46, nat46_xlate_rule_t *rule, void *pipv6, void *pipv4) { 433 | char *ipv4 = pipv4; 434 | char *ipv6 = pipv6; 435 | int cmp = -1; 436 | int v6_pref_len = rule->v6_pref_len; 437 | 438 | switch(v6_pref_len) { 439 | case 32: 440 | cmp = memcmp(ipv6, &rule->v6_pref, 4); 441 | break; 442 | case 40: 443 | cmp = memcmp(ipv6, &rule->v6_pref, 5); 444 | break; 445 | case 48: 446 | cmp = memcmp(ipv6, &rule->v6_pref, 6); 447 | break; 448 | case 56: 449 | cmp = memcmp(ipv6, &rule->v6_pref, 7); 450 | break; 451 | case 64: 452 | cmp = memcmp(ipv6, &rule->v6_pref, 8); 453 | break; 454 | case 96: 455 | cmp = memcmp(ipv6, &rule->v6_pref, 12); 456 | break; 457 | } 458 | if (cmp) { 459 | /* Not in NAT64 prefix */ 460 | return 0; 461 | } 462 | switch(v6_pref_len) { 463 | case 32: 464 | memcpy(ipv4, &ipv6[4], 4); 465 | break; 466 | case 40: 467 | memcpy(ipv4, &ipv6[5], 3); 468 | ipv4[3] = ipv6[9]; 469 | break; 470 | case 48: 471 | ipv4[0] = ipv6[6]; 472 | ipv4[1] = ipv6[7]; 473 | ipv4[2] = ipv6[9]; 474 | ipv4[3] = ipv6[10]; 475 | break; 476 | case 56: 477 | ipv4[0] = ipv6[7]; 478 | ipv4[1] = ipv6[9]; 479 | ipv4[2] = ipv6[10]; 480 | ipv4[3] = ipv6[11]; 481 | break; 482 | case 64: 483 | memcpy(ipv4, &ipv6[9], 4); 484 | break; 485 | case 96: 486 | memcpy(ipv4, &ipv6[12], 4); 487 | break; 488 | } 489 | return 1; 490 | } 491 | 492 | /* 493 | 494 | The below bitarray copy code is from 495 | 496 | http://stackoverflow.com/questions/3534535/whats-a-time-efficient-algorithm-to-copy-unaligned-bit-arrays 497 | 498 | */ 499 | 500 | #define CHAR_BIT 8 501 | #define PREPARE_FIRST_COPY() \ 502 | do { \ 503 | if (src_len >= (CHAR_BIT - dst_offset_modulo)) { \ 504 | *dst &= reverse_mask[dst_offset_modulo]; \ 505 | src_len -= CHAR_BIT - dst_offset_modulo; \ 506 | } else { \ 507 | *dst &= reverse_mask[dst_offset_modulo] \ 508 | | reverse_mask_xor[dst_offset_modulo + src_len + 1];\ 509 | c &= reverse_mask[dst_offset_modulo + src_len ];\ 510 | src_len = 0; \ 511 | } } while (0) 512 | 513 | 514 | static void 515 | bitarray_copy(const void *src_org, int src_offset, int src_len, 516 | void *dst_org, int dst_offset) 517 | { 518 | /* 519 | static const unsigned char mask[] = 520 | { 0x55, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; 521 | */ 522 | static const unsigned char reverse_mask[] = 523 | { 0x55, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 524 | static const unsigned char reverse_mask_xor[] = 525 | { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00 }; 526 | 527 | if (src_len) { 528 | const unsigned char *src; 529 | unsigned char *dst; 530 | int src_offset_modulo, 531 | dst_offset_modulo; 532 | 533 | src = src_org + (src_offset / CHAR_BIT); 534 | dst = dst_org + (dst_offset / CHAR_BIT); 535 | 536 | src_offset_modulo = src_offset % CHAR_BIT; 537 | dst_offset_modulo = dst_offset % CHAR_BIT; 538 | 539 | if (src_offset_modulo == dst_offset_modulo) { 540 | int byte_len; 541 | int src_len_modulo; 542 | if (src_offset_modulo) { 543 | unsigned char c; 544 | 545 | c = reverse_mask_xor[dst_offset_modulo] & *src++; 546 | 547 | PREPARE_FIRST_COPY(); 548 | *dst++ |= c; 549 | } 550 | 551 | byte_len = src_len / CHAR_BIT; 552 | src_len_modulo = src_len % CHAR_BIT; 553 | 554 | if (byte_len) { 555 | memcpy(dst, src, byte_len); 556 | src += byte_len; 557 | dst += byte_len; 558 | } 559 | if (src_len_modulo) { 560 | *dst &= reverse_mask_xor[src_len_modulo]; 561 | *dst |= reverse_mask[src_len_modulo] & *src; 562 | } 563 | } else { 564 | int bit_diff_ls, 565 | bit_diff_rs; 566 | int byte_len; 567 | int src_len_modulo; 568 | unsigned char c; 569 | /* 570 | * Begin: Line things up on destination. 571 | */ 572 | if (src_offset_modulo > dst_offset_modulo) { 573 | bit_diff_ls = src_offset_modulo - dst_offset_modulo; 574 | bit_diff_rs = CHAR_BIT - bit_diff_ls; 575 | 576 | c = *src++ << bit_diff_ls; 577 | c |= *src >> bit_diff_rs; 578 | c &= reverse_mask_xor[dst_offset_modulo]; 579 | } else { 580 | bit_diff_rs = dst_offset_modulo - src_offset_modulo; 581 | bit_diff_ls = CHAR_BIT - bit_diff_rs; 582 | 583 | c = *src >> bit_diff_rs & 584 | reverse_mask_xor[dst_offset_modulo]; 585 | } 586 | PREPARE_FIRST_COPY(); 587 | *dst++ |= c; 588 | 589 | /* 590 | * Middle: copy with only shifting the source. 591 | */ 592 | byte_len = src_len / CHAR_BIT; 593 | 594 | while (--byte_len >= 0) { 595 | c = *src++ << bit_diff_ls; 596 | c |= *src >> bit_diff_rs; 597 | *dst++ = c; 598 | } 599 | 600 | /* 601 | * End: copy the remaining bits; 602 | */ 603 | src_len_modulo = src_len % CHAR_BIT; 604 | if (src_len_modulo) { 605 | c = *src++ << bit_diff_ls; 606 | c |= *src >> bit_diff_rs; 607 | c &= reverse_mask[src_len_modulo]; 608 | 609 | *dst &= reverse_mask_xor[src_len_modulo]; 610 | *dst |= c; 611 | } 612 | } 613 | } 614 | } 615 | 616 | static int xlate_map_v4_to_v6(nat46_instance_t *nat46, nat46_xlate_rule_t *rule, void *pipv4, void *pipv6, uint16_t *pl4id, int map_version) { 617 | int ret = 0; 618 | u32 *pv4u32 = pipv4; 619 | uint8_t *p6 = pipv6; 620 | 621 | uint16_t psid; 622 | uint16_t l4id = pl4id ? *pl4id : 0; 623 | uint8_t psid_bits_len = rule->ea_len - (32 - rule->v4_pref_len); 624 | uint8_t v4_lsb_bits_len = 32 - rule->v4_pref_len; 625 | 626 | /* check that the ipv4 address is within the IPv4 map domain and reject if not */ 627 | 628 | if ( (ntohl(*pv4u32) & (0xffffffff << v4_lsb_bits_len)) != ntohl(rule->v4_pref) ) { 629 | nat46debug(5, "xlate_map_v4_to_v6: IPv4 address %pI4 outside of MAP domain %pI4/%d", pipv4, &rule->v4_pref, rule->v4_pref_len); 630 | return 0; 631 | } 632 | 633 | if (rule->ea_len < (32 - rule->v4_pref_len) ) { 634 | nat46debug(0, "xlate_map_v4_to_v6: rule->ea_len < (32 - rule->v4_pref_len)"); 635 | return 0; 636 | } 637 | 638 | if (!pl4id && psid_bits_len) { 639 | nat46debug(5, "xlate_map_v4_to_v6: l4id required for MAP domain %pI4/%d (ea-len %d)", &rule->v4_pref, rule->v4_pref_len, rule->ea_len); 640 | return 0; 641 | } 642 | 643 | /* zero out the IPv6 address */ 644 | memset(pipv6, 0, 16); 645 | 646 | psid = (ntohs(l4id) >> (16 - psid_bits_len - rule->psid_offset)) & (0xffff >> (16 - psid_bits_len)); 647 | nat46debug(10, "xlate_map_v4_to_v6: ntohs(l4id): %04x psid_bits_len: %d, rule psid-offset: %d, psid: %d\n", ntohs(l4id), psid_bits_len, rule->psid_offset, psid); 648 | 649 | /* 650 | * create the IID. pay the attention there can be two formats: 651 | * 652 | * draft-ietf-softwire-map-t-00: 653 | * 654 | * 655 | * +--+---+---+---+---+---+---+---+---+ 656 | * |PL| 8 16 24 32 40 48 56 | 657 | * +--+---+---+---+---+---+---+---+---+ 658 | * |64| u | IPv4 address | PSID | 0 | 659 | * +--+---+---+---+---+---+---+---+---+ 660 | * 661 | * 662 | * latest draft-ietf-softwire-map-t: 663 | * 664 | * | 128-n-o-s bits | 665 | * | 16 bits| 32 bits | 16 bits| 666 | * +--------+----------------+--------+ 667 | * | 0 | IPv4 address | PSID | 668 | * +--------+----------------+--------+ 669 | * 670 | * In the case of an IPv4 prefix, the IPv4 address field is right-padded 671 | * with zeros up to 32 bits. The PSID is zero left-padded to create a 672 | * 16 bit field. For an IPv4 prefix or a complete IPv4 address, the 673 | * PSID field is zero. 674 | * 675 | * If the End-user IPv6 prefix length is larger than 64, the most 676 | * significant parts of the interface identifier is overwritten by the 677 | * prefix. 678 | * 679 | */ 680 | if (map_version) { 681 | p6[8] = p6[9] = 0; 682 | p6[10] = 0xff & (ntohl(*pv4u32) >> 24); 683 | p6[11] = 0xff & (ntohl(*pv4u32) >> 16); 684 | p6[12] = 0xff & (ntohl(*pv4u32) >> 8); 685 | p6[13] = 0xff & (ntohl(*pv4u32)); 686 | p6[14] = 0xff & (psid >> 8); 687 | p6[15] = 0xff & (psid); 688 | } else { 689 | p6[8] = 0; 690 | p6[9] = 0xff & (ntohl(*pv4u32) >> 24); 691 | p6[10] = 0xff & (ntohl(*pv4u32) >> 16); 692 | p6[11] = 0xff & (ntohl(*pv4u32) >> 8); 693 | p6[12] = 0xff & (ntohl(*pv4u32)); 694 | p6[13] = 0xff & (psid >> 8); 695 | p6[14] = 0xff & (psid); 696 | p6[15] = 0; 697 | /* old EID */ 698 | } 699 | 700 | /* copy the necessary part of domain IPv6 prefix into place, w/o overwriting the existing data */ 701 | bitarray_copy(&rule->v6_pref, 0, rule->v6_pref_len, p6, 0); 702 | 703 | if (v4_lsb_bits_len) { 704 | /* insert the lower 32-v4_pref_len bits of IPv4 address at rule->v6_pref_len */ 705 | bitarray_copy(pipv4, rule->v4_pref_len, v4_lsb_bits_len, p6, rule->v6_pref_len); 706 | } 707 | 708 | if (psid_bits_len) { 709 | /* insert the psid bits at rule->v6_pref_len + v4_lsb_bits */ 710 | bitarray_copy(&l4id, rule->psid_offset, psid_bits_len, p6, rule->v6_pref_len + v4_lsb_bits_len); 711 | } 712 | 713 | ret = 1; 714 | 715 | return ret; 716 | } 717 | 718 | static int xlate_map_v6_to_v4(nat46_instance_t *nat46, nat46_xlate_rule_t *rule, void *pipv6, void *pipv4, int version) { 719 | uint8_t v4_lsb_bits_len = 32 - rule->v4_pref_len; 720 | 721 | if (memcmp(pipv6, &rule->v6_pref, rule->v6_pref_len/8)) { 722 | /* address not within the MAP IPv6 prefix */ 723 | nat46debug(5, "xlate_map_v6_to_v4: IPv6 address %pI6 outside of MAP domain %pI6/%d", pipv6, &rule->v6_pref, rule->v6_pref_len); 724 | return 0; 725 | } 726 | if (rule->v6_pref_len % 8) { 727 | uint8_t mask = 0xff << (8 - (rule->v6_pref_len % 8)); 728 | uint8_t *pa1 = (uint8_t *)pipv6 + (rule->v6_pref_len/8); 729 | uint8_t *pa2 = (uint8_t *)&rule->v6_pref + (rule->v6_pref_len/8); 730 | 731 | if ( (*pa1 & mask) != (*pa2 & mask) ) { 732 | nat46debug(5, "xlate_map_v6_to_v4: IPv6 address %pI6 outside of MAP domain %pI6/%d (LSB)", pipv6, &rule->v6_pref, rule->v6_pref_len); 733 | return 0; 734 | } 735 | } 736 | 737 | if (rule->ea_len < (32 - rule->v4_pref_len) ) { 738 | nat46debug(0, "xlate_map_v6_to_v4: rule->ea_len < (32 - rule->v4_pref_len)"); 739 | return 0; 740 | } 741 | 742 | memcpy(pipv4, &rule->v4_pref, 4); 743 | if (v4_lsb_bits_len) { 744 | bitarray_copy(pipv6, rule->v6_pref_len, v4_lsb_bits_len, pipv4, rule->v4_pref_len); 745 | } 746 | /* 747 | * I do not verify the PSID here. The idea is that if the destination port is incorrect, this 748 | * will be caught in the NAT44 module. 749 | */ 750 | return 1; 751 | } 752 | 753 | static int xlate_v4_to_v6(nat46_instance_t *nat46, nat46_xlate_rule_t *rule, void *pipv4, void *pipv6, uint16_t *pl4id) { 754 | int ret = 0; 755 | switch(rule->style) { 756 | case NAT46_XLATE_NONE: /* always fail unless it is a host 1:1 translation */ 757 | if ( (rule->v6_pref_len == 128) && (rule->v4_pref_len == 32) && 758 | (0 == memcmp(pipv4, &rule->v4_pref, sizeof(rule->v4_pref))) ) { 759 | memcpy(pipv6, &rule->v6_pref, sizeof(rule->v6_pref)); 760 | ret = 1; 761 | } 762 | break; 763 | case NAT46_XLATE_MAP0: 764 | ret = xlate_map_v4_to_v6(nat46, rule, pipv4, pipv6, pl4id, 0); 765 | break; 766 | case NAT46_XLATE_MAP: 767 | ret = xlate_map_v4_to_v6(nat46, rule, pipv4, pipv6, pl4id, 1); 768 | break; 769 | case NAT46_XLATE_RFC6052: 770 | xlate_v4_to_nat64(nat46, rule, pipv4, pipv6); 771 | /* NAT46 rules using RFC6052 always succeed since they can map any IPv4 address */ 772 | ret = 1; 773 | break; 774 | } 775 | return ret; 776 | } 777 | 778 | static int xlate_v6_to_v4(nat46_instance_t *nat46, nat46_xlate_rule_t *rule, void *pipv6, void *pipv4) { 779 | int ret = 0; 780 | switch(rule->style) { 781 | case NAT46_XLATE_NONE: /* always fail unless it is a host 1:1 translation */ 782 | if ( (rule->v6_pref_len == 128) && (rule->v4_pref_len == 32) && 783 | (0 == memcmp(pipv6, &rule->v6_pref, sizeof(rule->v6_pref))) ) { 784 | memcpy(pipv4, &rule->v4_pref, sizeof(rule->v4_pref)); 785 | ret = 1; 786 | } 787 | break; 788 | case NAT46_XLATE_MAP0: 789 | ret = xlate_map_v6_to_v4(nat46, rule, pipv6, pipv4, 0); 790 | break; 791 | case NAT46_XLATE_MAP: 792 | ret = xlate_map_v6_to_v4(nat46, rule, pipv6, pipv4, 1); 793 | break; 794 | case NAT46_XLATE_RFC6052: 795 | ret = xlate_nat64_to_v4(nat46, rule, pipv6, pipv4); 796 | break; 797 | } 798 | return ret; 799 | } 800 | 801 | static __sum16 csum16_upd(__sum16 csum, u16 old, u16 new) { 802 | u32 s; 803 | csum = ntohs(~csum); 804 | s = (u32)csum + ntohs(~old) + ntohs(new); 805 | s = ((s >> 16) & 0xffff) + (s & 0xffff); 806 | s += ((s >> 16) & 0xffff); 807 | return htons((u16)(~s)); 808 | } 809 | 810 | /* Add the TCP/UDP pseudoheader, basing on the existing checksum */ 811 | 812 | static __sum16 csum_tcpudp_remagic(__be32 saddr, __be32 daddr, u32 len, 813 | unsigned char proto, u16 csum) { 814 | u16 *pdata; 815 | u16 len0, len1; 816 | 817 | pdata = (u16 *)&saddr; 818 | csum = csum16_upd(csum, 0, *pdata++); 819 | csum = csum16_upd(csum, 0, *pdata++); 820 | pdata = (u16 *)&daddr; 821 | csum = csum16_upd(csum, 0, *pdata++); 822 | csum = csum16_upd(csum, 0, *pdata++); 823 | 824 | csum = csum16_upd(csum, 0, htons(proto)); 825 | len1 = htons( (len >> 16) & 0xffff ); 826 | len0 = htons(len & 0xffff); 827 | csum = csum16_upd(csum, 0, len1); 828 | csum = csum16_upd(csum, 0, len0); 829 | return csum; 830 | } 831 | 832 | /* Undo the IPv6 pseudoheader inclusion into the checksum */ 833 | static __sum16 csum_ipv6_unmagic(nat46_instance_t *nat46, const struct in6_addr *saddr, 834 | const struct in6_addr *daddr, 835 | __u32 len, unsigned short proto, 836 | __sum16 csum) { 837 | u16 *pdata; 838 | int i; 839 | u16 len0, len1; 840 | 841 | pdata = (u16 *)saddr; 842 | for(i=0;i<8;i++) { 843 | csum = csum16_upd(csum, *pdata, 0); 844 | pdata++; 845 | } 846 | pdata = (u16 *)daddr; 847 | for(i=0;i<8;i++) { 848 | csum = csum16_upd(csum, *pdata, 0); 849 | pdata++; 850 | } 851 | csum = csum16_upd(csum, htons(proto), 0); 852 | len1 = htons( (len >> 16) & 0xffff ); 853 | len0 = htons(len & 0xffff); 854 | csum = csum16_upd(csum, len1, 0); 855 | csum = csum16_upd(csum, len0, 0); 856 | return csum; 857 | } 858 | 859 | /* Update ICMPv6 type/code with incremental checksum adjustment */ 860 | static void update_icmp6_type_code(nat46_instance_t *nat46, struct icmp6hdr *icmp6h, u8 type, u8 code) { 861 | u16 old_tc = *((u16 *)icmp6h); 862 | u16 new_tc; 863 | u16 old_csum = icmp6h->icmp6_cksum; 864 | u16 new_csum; 865 | icmp6h->icmp6_type = type; 866 | icmp6h->icmp6_code = code; 867 | new_tc = *((u16 *)icmp6h); 868 | /* https://tools.ietf.org/html/rfc1624 */ 869 | new_csum = csum16_upd(old_csum, old_tc, new_tc); 870 | nat46debug(1, "Updating the ICMPv6 type to ICMP type %d and code to %d. Old T/C: %04X, New T/C: %04X, Old CS: %04X, New CS: %04X", type, code, old_tc, new_tc, old_csum, new_csum); 871 | icmp6h->icmp6_cksum = new_csum; 872 | } 873 | 874 | 875 | static u16 get_next_ip_id(void) { 876 | static u16 id = 0; 877 | return id++; 878 | } 879 | 880 | static u16 fold_ipv6_frag_id(u32 v6id) { 881 | return ((0xffff & (v6id >> 16)) ^ (v6id & 0xffff)); 882 | } 883 | 884 | static void *add_offset(void *ptr, u16 offset) { 885 | return (((char *)ptr)+offset); 886 | } 887 | 888 | 889 | /* FIXME: traverse the headers properly */ 890 | static void *get_next_header_ptr6(void *pv6, int v6_len) { 891 | struct ipv6hdr *ip6h = pv6; 892 | void *ret = (ip6h+1); 893 | 894 | if (ip6h->nexthdr == NEXTHDR_FRAGMENT) { 895 | struct frag_hdr *fh = (struct frag_hdr*)(ip6h + 1); 896 | if(fh->frag_off == 0) { 897 | /* Atomic fragment */ 898 | ret = add_offset(ret, 8); 899 | } 900 | } 901 | return ret; 902 | } 903 | 904 | static void fill_v4hdr_from_v6hdr(struct iphdr * iph, struct ipv6hdr *ip6h, __u32 v4saddr, __u32 v4daddr, __u16 id, __u16 frag_off, __u16 proto, int l3_payload_len) { 905 | iph->ttl = ip6h->hop_limit; 906 | iph->saddr = v4saddr; 907 | iph->daddr = v4daddr; 908 | iph->protocol = proto; 909 | *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (0x00/*tos*/ & 0xff)); 910 | iph->frag_off = frag_off; 911 | iph->id = id; 912 | iph->tot_len = htons( l3_payload_len + IPV4HDRSIZE ); 913 | iph->check = 0; 914 | iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); 915 | } 916 | 917 | static u16 unchecksum16(void *p, int count, u16 csum) { 918 | u16 *pu16 = p; 919 | int i = count; 920 | while(i--) { 921 | csum = csum16_upd(csum, *pu16++, 0); 922 | } 923 | return csum; 924 | } 925 | 926 | static u16 rechecksum16(void *p, int count, u16 csum) { 927 | u16 *pu16 = p; 928 | int i = count; 929 | while(i--) { 930 | csum = csum16_upd(csum, 0, *pu16++); 931 | } 932 | return csum; 933 | } 934 | 935 | /* Last rule in group must not have "none" as either source or destination */ 936 | static int is_last_pair_in_group(nat46_xlate_rulepair_t *apair) { 937 | return ( (apair->local.style != NAT46_XLATE_NONE) && (apair->remote.style != NAT46_XLATE_NONE) ); 938 | } 939 | 940 | static void pairs_xlate_v6_to_v4_inner(nat46_instance_t *nat46, struct ipv6hdr *ip6h, __u32 *pv4saddr, __u32 *pv4daddr) { 941 | int ipair = 0; 942 | nat46_xlate_rulepair_t *apair = NULL; 943 | int xlate_src = -1; 944 | int xlate_dst = -1; 945 | 946 | for(ipair = 0; ipair < nat46->npairs; ipair++) { 947 | apair = &nat46->pairs[ipair]; 948 | 949 | if(-1 == xlate_dst) { 950 | if(xlate_v6_to_v4(nat46, &apair->remote, &ip6h->daddr, pv4daddr)) { 951 | xlate_dst = ipair; 952 | } 953 | } 954 | if(-1 == xlate_src) { 955 | if(xlate_v6_to_v4(nat46, &apair->local, &ip6h->saddr, pv4saddr)) { 956 | xlate_src = ipair; 957 | } 958 | } 959 | if((xlate_src >= 0) && (xlate_dst >= 0)) { 960 | /* we did manage to translate it */ 961 | break; 962 | } else { 963 | /* We did not match fully and there are more rules */ 964 | if((ipair+1 < nat46->npairs) && is_last_pair_in_group(apair)) { 965 | xlate_src = -1; 966 | xlate_dst = -1; 967 | } 968 | } 969 | } 970 | nat46debug(5, "[nat46payload] xlate results: src %d dst %d", xlate_src, xlate_dst); 971 | } 972 | 973 | /* 974 | * pv6 is pointing to the ipv6 header inside the payload. 975 | * Translate this header and attempt to extract the sport/dport 976 | * so the callers can use them for translation as well. 977 | */ 978 | static int xlate_payload6_to4(nat46_instance_t *nat46, void *pv6, void *ptrans_hdr, int v6_len, u16 *ul_sum, int *ptailTruncSize) { 979 | struct ipv6hdr *ip6h = pv6; 980 | __u32 v4saddr, v4daddr; 981 | struct iphdr new_ipv4; 982 | struct iphdr *iph = &new_ipv4; 983 | u16 proto = ip6h->nexthdr; 984 | u16 ipid = 0; 985 | u16 ipflags = htons(IP_DF); 986 | int infrag_payload_len = ntohs(ip6h->payload_len); 987 | 988 | /* 989 | * The packet is supposedly our own packet after translation - so the rules 990 | * will be swapped compared to translation of the outer packet 991 | */ 992 | pairs_xlate_v6_to_v4_inner(nat46, pv6, &v4saddr, &v4daddr); 993 | 994 | if (proto == NEXTHDR_FRAGMENT) { 995 | struct frag_hdr *fh = (struct frag_hdr*)(ip6h + 1); 996 | if(fh->frag_off == 0) { 997 | /* Atomic fragment */ 998 | proto = fh->nexthdr; 999 | ipid = fold_ipv6_frag_id(fh->identification); 1000 | v6_len -= 8; 1001 | infrag_payload_len -= 8; 1002 | *ptailTruncSize += 8; 1003 | ipflags = 0; 1004 | } 1005 | } 1006 | 1007 | 1008 | switch(proto) { 1009 | case NEXTHDR_TCP: { 1010 | struct tcphdr *th = ptrans_hdr; 1011 | u16 sum1 = csum_ipv6_unmagic(nat46, &ip6h->saddr, &ip6h->daddr, infrag_payload_len, NEXTHDR_TCP, th->check); 1012 | u16 sum2 = csum_tcpudp_remagic(v4saddr, v4daddr, infrag_payload_len, NEXTHDR_TCP, sum1); /* add pseudoheader */ 1013 | if(ul_sum) { 1014 | *ul_sum = csum16_upd(*ul_sum, th->check, sum2); 1015 | } 1016 | th->check = sum2; 1017 | break; 1018 | } 1019 | case NEXTHDR_UDP: { 1020 | struct udphdr *udp = ptrans_hdr; 1021 | u16 sum1, sum2; 1022 | if ((udp->check == 0) && zero_csum_pass) { 1023 | /* zero checksum and the config to pass it is set - do nothing with it */ 1024 | break; 1025 | } 1026 | sum1 = csum_ipv6_unmagic(nat46, &ip6h->saddr, &ip6h->daddr, infrag_payload_len, NEXTHDR_UDP, udp->check); 1027 | sum2 = csum_tcpudp_remagic(v4saddr, v4daddr, infrag_payload_len, NEXTHDR_UDP, sum1); /* add pseudoheader */ 1028 | if(ul_sum) { 1029 | *ul_sum = csum16_upd(*ul_sum, udp->check, sum2); 1030 | } 1031 | udp->check = sum2; 1032 | break; 1033 | } 1034 | case NEXTHDR_ICMP: { 1035 | struct icmp6hdr *icmp6h = ptrans_hdr; 1036 | u16 sum0 = icmp6h->icmp6_cksum; 1037 | u16 sum1 = csum_ipv6_unmagic(nat46, &ip6h->saddr, &ip6h->daddr, infrag_payload_len, NEXTHDR_ICMP, icmp6h->icmp6_cksum); 1038 | if(ul_sum) { 1039 | *ul_sum = csum16_upd(*ul_sum, sum0, sum1); 1040 | } 1041 | icmp6h->icmp6_cksum = sum1; 1042 | proto = IPPROTO_ICMP; 1043 | switch(icmp6h->icmp6_type) { 1044 | case ICMPV6_ECHO_REQUEST: 1045 | update_icmp6_type_code(nat46, icmp6h, ICMP_ECHO, icmp6h->icmp6_code); 1046 | break; 1047 | case ICMPV6_ECHO_REPLY: 1048 | update_icmp6_type_code(nat46, icmp6h, ICMP_ECHOREPLY, icmp6h->icmp6_code); 1049 | break; 1050 | default: 1051 | break; 1052 | } 1053 | } 1054 | } 1055 | 1056 | fill_v4hdr_from_v6hdr(iph, ip6h, v4saddr, v4daddr, ipid, ipflags, proto, infrag_payload_len); 1057 | if(ul_sum) { 1058 | *ul_sum = unchecksum16(pv6, (((u8 *)ptrans_hdr)-((u8 *)pv6))/2, *ul_sum); 1059 | *ul_sum = rechecksum16(iph, 10, *ul_sum); 1060 | } 1061 | 1062 | memmove(((char *)pv6) + IPV4HDRSIZE, get_next_header_ptr6(ip6h, v6_len), v6_len - IPV4HDRSIZE); 1063 | memcpy(pv6, iph, IPV4HDRSIZE); 1064 | *ptailTruncSize += IPV6V4HDRDELTA; 1065 | return (v6_len - IPV6V4HDRDELTA); 1066 | } 1067 | 1068 | static u8 *icmp_parameter_ptr(struct icmphdr *icmph) { 1069 | u8 *icmp_pptr = ((u8 *)(icmph))+4; 1070 | return icmp_pptr; 1071 | } 1072 | 1073 | static u32 *icmp6_parameter_ptr(struct icmp6hdr *icmp6h) { 1074 | u32 *icmp6_pptr = ((u32 *)(icmp6h))+1; 1075 | return icmp6_pptr; 1076 | } 1077 | 1078 | static void nat46_fixup_icmp6_dest_unreach(nat46_instance_t *nat46, struct ipv6hdr *ip6h, struct icmp6hdr *icmp6h, struct sk_buff *old_skb, int *ptailTruncSize) { 1079 | /* 1080 | * Destination Unreachable (Type 1) Set the Type to 3, and adjust 1081 | * the ICMP checksum both to take the type/code change into 1082 | * account and to exclude the ICMPv6 pseudo-header. 1083 | * 1084 | * Translate the Code as follows: 1085 | * 1086 | * Code 0 (No route to destination): Set the Code to 1 (Host 1087 | * unreachable). 1088 | * 1089 | * Code 1 (Communication with destination administratively 1090 | * prohibited): Set the Code to 10 (Communication with 1091 | * destination host administratively prohibited). 1092 | * 1093 | * Code 2 (Beyond scope of source address): Set the Code to 1 1094 | * (Host unreachable). Note that this error is very unlikely 1095 | * since an IPv4-translatable source address is typically 1096 | * considered to have global scope. 1097 | * 1098 | * Code 3 (Address unreachable): Set the Code to 1 (Host 1099 | * unreachable). 1100 | * 1101 | * Code 4 (Port unreachable): Set the Code to 3 (Port 1102 | * unreachable). 1103 | * 1104 | * Other Code values: Silently drop. 1105 | */ 1106 | 1107 | int len; 1108 | 1109 | switch(icmp6h->icmp6_code) { 1110 | case 0: 1111 | case 2: 1112 | case 3: 1113 | update_icmp6_type_code(nat46, icmp6h, 3, 1); 1114 | break; 1115 | case 1: 1116 | update_icmp6_type_code(nat46, icmp6h, 3, 10); 1117 | break; 1118 | case 4: 1119 | update_icmp6_type_code(nat46, icmp6h, 3, 3); 1120 | break; 1121 | default: 1122 | ip6h->nexthdr = NEXTHDR_NONE; 1123 | } 1124 | len = ntohs(ip6h->payload_len)-sizeof(*icmp6h); 1125 | len = xlate_payload6_to4(nat46, (icmp6h + 1), get_next_header_ptr6((icmp6h + 1), len), len, &icmp6h->icmp6_cksum, ptailTruncSize); 1126 | } 1127 | 1128 | static void nat46_fixup_icmp6_pkt_toobig(nat46_instance_t *nat46, struct ipv6hdr *ip6h, struct icmp6hdr *icmp6h, struct sk_buff *old_skb, int *ptailTruncSize) { 1129 | /* 1130 | * Packet Too Big (Type 2): Translate to an ICMPv4 Destination 1131 | * Unreachable (Type 3) with Code 4, and adjust the ICMPv4 1132 | * checksum both to take the type change into account and to 1133 | * exclude the ICMPv6 pseudo-header. The MTU field MUST be 1134 | * adjusted for the difference between the IPv4 and IPv6 header 1135 | * sizes, taking into account whether or not the packet in error 1136 | * includes a Fragment Header, i.e., minimum(advertised MTU-20, 1137 | * MTU_of_IPv4_nexthop, (MTU_of_IPv6_nexthop)-20). 1138 | * 1139 | * See also the requirements in Section 6. 1140 | * 1141 | * Section 6 says this for v6->v4 side translation: 1142 | * 1143 | * 2. In the IPv6-to-IPv4 direction: 1144 | * 1145 | * A. If there is a Fragment Header in the IPv6 packet, the last 16 1146 | * bits of its value MUST be used for the IPv4 identification 1147 | * value. 1148 | * 1149 | * B. If there is no Fragment Header in the IPv6 packet: 1150 | * 1151 | * a. If the packet is less than or equal to 1280 bytes: 1152 | * 1153 | * - The translator SHOULD set DF to 0 and generate an IPv4 1154 | * identification value. 1155 | * 1156 | * - To avoid the problems described in [RFC4963], it is 1157 | * RECOMMENDED that the translator maintain 3-tuple state 1158 | * for generating the IPv4 identification value. 1159 | * 1160 | * b. If the packet is greater than 1280 bytes, the translator 1161 | * SHOULD set the IPv4 DF bit to 1. 1162 | */ 1163 | int len = ntohs(ip6h->payload_len)-sizeof(*icmp6h); 1164 | u16 *pmtu = ((u16 *)icmp6h) + 3; /* IPv4-compatible MTU value is 16 bit */ 1165 | u16 old_csum = icmp6h->icmp6_cksum; 1166 | 1167 | if (ntohs(*pmtu) > IPV6V4HDRDELTA) { 1168 | icmp6h->icmp6_cksum = csum16_upd(old_csum, *pmtu, htons(ntohs(*pmtu) - IPV6V4HDRDELTA)); 1169 | *pmtu = htons(ntohs(*pmtu) - IPV6V4HDRDELTA); 1170 | } 1171 | 1172 | len = xlate_payload6_to4(nat46, (icmp6h + 1), get_next_header_ptr6((icmp6h + 1), len), len, &icmp6h->icmp6_cksum, ptailTruncSize); 1173 | 1174 | update_icmp6_type_code(nat46, icmp6h, 3, 4); 1175 | 1176 | } 1177 | 1178 | static void nat46_fixup_icmp6_time_exceed(nat46_instance_t *nat46, struct ipv6hdr *ip6h, struct icmp6hdr *icmp6h, struct sk_buff *old_skb, int *ptailTruncSize) { 1179 | /* 1180 | * Time Exceeded (Type 3): Set the Type to 11, and adjust the ICMPv4 1181 | * checksum both to take the type change into account and to 1182 | * exclude the ICMPv6 pseudo-header. The Code is unchanged. 1183 | */ 1184 | int len = ntohs(ip6h->payload_len)-sizeof(*icmp6h); 1185 | len = xlate_payload6_to4(nat46, (icmp6h + 1), get_next_header_ptr6((icmp6h + 1), len), len, &icmp6h->icmp6_cksum, ptailTruncSize); 1186 | 1187 | update_icmp6_type_code(nat46, icmp6h, 11, icmp6h->icmp6_code); 1188 | } 1189 | 1190 | static void nat46_fixup_icmp6_paramprob(nat46_instance_t *nat46, struct ipv6hdr *ip6h, struct icmp6hdr *icmp6h, struct sk_buff *old_skb, int *ptailTruncSize) { 1191 | /* 1192 | * Parameter Problem (Type 4): Translate the Type and Code as 1193 | * follows, and adjust the ICMPv4 checksum both to take the type/ 1194 | * code change into account and to exclude the ICMPv6 pseudo- 1195 | * header. 1196 | * 1197 | * Translate the Code as follows: 1198 | * 1199 | * Code 0 (Erroneous header field encountered): Set to Type 12, 1200 | * Code 0, and update the pointer as defined in Figure 6. (If 1201 | * the Original IPv6 Pointer Value is not listed or the 1202 | * Translated IPv4 Pointer Value is listed as "n/a", silently 1203 | * drop the packet.) 1204 | * 1205 | * Code 1 (Unrecognized Next Header type encountered): Translate 1206 | * this to an ICMPv4 protocol unreachable (Type 3, Code 2). 1207 | * 1208 | * Code 2 (Unrecognized IPv6 option encountered): Silently drop. 1209 | * 1210 | * Unknown error messages: Silently drop. 1211 | * 1212 | * +--------------------------------+--------------------------------+ 1213 | * | Original IPv6 Pointer Value | Translated IPv4 Pointer Value | 1214 | * +--------------------------------+--------------------------------+ 1215 | * | 0 | Version/Traffic Class | 0 | Version/IHL, Type Of Ser | 1216 | * | 1 | Traffic Class/Flow Label | 1 | Type Of Service | 1217 | * | 2,3 | Flow Label | n/a | | 1218 | * | 4,5 | Payload Length | 2 | Total Length | 1219 | * | 6 | Next Header | 9 | Protocol | 1220 | * | 7 | Hop Limit | 8 | Time to Live | 1221 | * | 8-23| Source Address | 12 | Source Address | 1222 | * |24-39| Destination Address | 16 | Destination Address | 1223 | * +--------------------------------+--------------------------------+ 1224 | */ 1225 | static int ptr6_4[] = { 0, 1, -1, -1, 2, 2, 9, 8, 1226 | 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 1227 | 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, -1 }; 1228 | u32 *pptr6 = icmp6_parameter_ptr(icmp6h); 1229 | u8 *pptr4 = icmp_parameter_ptr((struct icmphdr *)icmp6h); 1230 | int new_pptr = -1; 1231 | int len = ntohs(ip6h->payload_len)-sizeof(*icmp6h); 1232 | 1233 | switch(icmp6h->icmp6_code) { 1234 | case 0: 1235 | if(*pptr6 < sizeof(ptr6_4)/sizeof(ptr6_4[0])) { 1236 | new_pptr = ptr6_4[*pptr6]; 1237 | if (new_pptr >= 0) { 1238 | icmp6h->icmp6_cksum = csum16_upd(icmp6h->icmp6_cksum, (*pptr6 & 0xffff), (new_pptr << 8)); 1239 | *pptr4 = 0xff & new_pptr; 1240 | update_icmp6_type_code(nat46, icmp6h, 12, 0); 1241 | len = xlate_payload6_to4(nat46, (icmp6h + 1), get_next_header_ptr6((icmp6h + 1), len), len, &icmp6h->icmp6_cksum, ptailTruncSize); 1242 | } else { 1243 | ip6h->nexthdr = NEXTHDR_NONE; 1244 | } 1245 | } else { 1246 | ip6h->nexthdr = NEXTHDR_NONE; 1247 | } 1248 | break; 1249 | case 1: 1250 | icmp6h->icmp6_cksum = csum16_upd(icmp6h->icmp6_cksum, ((*pptr6 >> 16) & 0xffff), 0); 1251 | icmp6h->icmp6_cksum = csum16_upd(icmp6h->icmp6_cksum, (*pptr6 & 0xffff), 0); 1252 | *pptr6 = 0; 1253 | update_icmp6_type_code(nat46, icmp6h, 3, 2); 1254 | len = xlate_payload6_to4(nat46, (icmp6h + 1), get_next_header_ptr6((icmp6h + 1), len), len, &icmp6h->icmp6_cksum, ptailTruncSize); 1255 | break; 1256 | case 2: /* fallthrough to default */ 1257 | default: 1258 | ip6h->nexthdr = NEXTHDR_NONE; 1259 | } 1260 | } 1261 | 1262 | 1263 | /* Fixup ICMP6->ICMP before IP header translation, according to http://tools.ietf.org/html/rfc6145 */ 1264 | 1265 | static void nat46_fixup_icmp6(nat46_instance_t *nat46, struct ipv6hdr *ip6h, struct icmp6hdr *icmp6h, struct sk_buff *old_skb, int *ptailTruncSize) { 1266 | 1267 | if(icmp6h->icmp6_type & 128) { 1268 | /* Informational ICMP */ 1269 | switch(icmp6h->icmp6_type) { 1270 | case ICMPV6_ECHO_REQUEST: 1271 | update_icmp6_type_code(nat46, icmp6h, ICMP_ECHO, icmp6h->icmp6_code); 1272 | break; 1273 | case ICMPV6_ECHO_REPLY: 1274 | update_icmp6_type_code(nat46, icmp6h, ICMP_ECHOREPLY, icmp6h->icmp6_code); 1275 | break; 1276 | default: 1277 | ip6h->nexthdr = NEXTHDR_NONE; 1278 | } 1279 | } else { 1280 | /* ICMPv6 errors */ 1281 | switch(icmp6h->icmp6_type) { 1282 | case ICMPV6_DEST_UNREACH: 1283 | nat46_fixup_icmp6_dest_unreach(nat46, ip6h, icmp6h, old_skb, ptailTruncSize); 1284 | break; 1285 | case ICMPV6_PKT_TOOBIG: 1286 | nat46_fixup_icmp6_pkt_toobig(nat46, ip6h, icmp6h, old_skb, ptailTruncSize); 1287 | break; 1288 | case ICMPV6_TIME_EXCEED: 1289 | nat46_fixup_icmp6_time_exceed(nat46, ip6h, icmp6h, old_skb, ptailTruncSize); 1290 | break; 1291 | case ICMPV6_PARAMPROB: 1292 | nat46_fixup_icmp6_paramprob(nat46, ip6h, icmp6h, old_skb, ptailTruncSize); 1293 | break; 1294 | default: 1295 | ip6h->nexthdr = NEXTHDR_NONE; 1296 | } 1297 | } 1298 | } 1299 | 1300 | 1301 | static int ip6_input_not_interested(nat46_instance_t *nat46, struct ipv6hdr *ip6h, struct sk_buff *old_skb) { 1302 | if (old_skb->protocol != htons(ETH_P_IPV6)) { 1303 | nat46debug(3, "Not an IPv6 packet"); 1304 | return 1; 1305 | } 1306 | if(old_skb->len < sizeof(struct ipv6hdr) || ip6h->version != 6) { 1307 | nat46debug(3, "Len short or not correct version: %d", ip6h->version); 1308 | return 1; 1309 | } 1310 | if (!(ipv6_addr_type(&ip6h->saddr) & IPV6_ADDR_UNICAST)) { 1311 | nat46debug(3, "Source address not unicast"); 1312 | return 1; 1313 | } 1314 | return 0; 1315 | } 1316 | 1317 | static uint16_t nat46_fixup_icmp_time_exceeded(nat46_instance_t *nat46, struct iphdr *iph, struct icmphdr *icmph, struct sk_buff *old_skb) { 1318 | /* 1319 | * Set the Type to 3, and adjust the 1320 | * ICMP checksum both to take the type change into account and 1321 | * to include the ICMPv6 pseudo-header. The Code is unchanged. 1322 | */ 1323 | icmph->type = 3; 1324 | return 0; 1325 | } 1326 | 1327 | static uint16_t nat46_fixup_icmp_parameterprob(nat46_instance_t *nat46, struct iphdr *iph, struct icmphdr *icmph, struct sk_buff *old_skb) { 1328 | /* 1329 | * Set the Type to 4, and adjust the 1330 | * ICMP checksum both to take the type/code change into account 1331 | * and to include the ICMPv6 pseudo-header. 1332 | * 1333 | * Translate the Code as follows: 1334 | * 1335 | * Code 0 (Pointer indicates the error): Set the Code to 0 1336 | * (Erroneous header field encountered) and update the 1337 | * pointer as defined in Figure 3. (If the Original IPv4 1338 | * Pointer Value is not listed or the Translated IPv6 1339 | * Pointer Value is listed as "n/a", silently drop the 1340 | * packet.) 1341 | * 1342 | * Code 1 (Missing a required option): Silently drop. 1343 | * 1344 | * Code 2 (Bad length): Set the Code to 0 (Erroneous header 1345 | * field encountered) and update the pointer as defined in 1346 | * Figure 3. (If the Original IPv4 Pointer Value is not 1347 | * listed or the Translated IPv6 Pointer Value is listed as 1348 | * "n/a", silently drop the packet.) 1349 | * 1350 | * Other Code values: Silently drop. 1351 | * 1352 | * +--------------------------------+--------------------------------+ 1353 | * | Original IPv4 Pointer Value | Translated IPv6 Pointer Value | 1354 | * +--------------------------------+--------------------------------+ 1355 | * | 0 | Version/IHL | 0 | Version/Traffic Class | 1356 | * | 1 | Type Of Service | 1 | Traffic Class/Flow Label | 1357 | * | 2,3 | Total Length | 4 | Payload Length | 1358 | * | 4,5 | Identification | n/a | | 1359 | * | 6 | Flags/Fragment Offset | n/a | | 1360 | * | 7 | Fragment Offset | n/a | | 1361 | * | 8 | Time to Live | 7 | Hop Limit | 1362 | * | 9 | Protocol | 6 | Next Header | 1363 | * |10,11| Header Checksum | n/a | | 1364 | * |12-15| Source Address | 8 | Source Address | 1365 | * |16-19| Destination Address | 24 | Destination Address | 1366 | * +--------------------------------+--------------------------------+ 1367 | */ 1368 | static int ptr4_6[] = { 0, 1, 4, 4, -1, -1, -1, -1, 7, 6, -1, -1, 8, 8, 8, 8, 24, 24, 24, 24, -1 }; 1369 | u8 *icmp_pptr = icmp_parameter_ptr(icmph); 1370 | int new_pptr = -1; 1371 | switch (icmph->code) { 1372 | case 0: 1373 | case 2: 1374 | if (*icmp_pptr < (sizeof(ptr4_6)/sizeof(ptr4_6[0]))) { 1375 | icmph->code = 0; 1376 | new_pptr = ptr4_6[*icmp_pptr]; 1377 | if(new_pptr >= 0) { 1378 | /* FIXME: update the parameter pointer in ICMPv6 with new_pptr value */ 1379 | } 1380 | } else { 1381 | iph->protocol = NEXTHDR_NONE; 1382 | } 1383 | break; 1384 | default: 1385 | iph->protocol = NEXTHDR_NONE; 1386 | } 1387 | return 0; 1388 | } 1389 | 1390 | static uint16_t nat46_fixup_icmp_dest_unreach(nat46_instance_t *nat46, struct iphdr *iph, struct icmphdr *icmph, struct sk_buff *old_skb) { 1391 | /* 1392 | * Translate the Code as 1393 | * described below, set the Type to 1, and adjust the ICMP 1394 | * checksum both to take the type/code change into account and 1395 | * to include the ICMPv6 pseudo-header. 1396 | * 1397 | * Translate the Code as follows: 1398 | * 1399 | * Code 0, 1 (Net Unreachable, Host Unreachable): Set the Code 1400 | * to 0 (No route to destination). 1401 | * 1402 | * Code 2 (Protocol Unreachable): Translate to an ICMPv6 1403 | * Parameter Problem (Type 4, Code 1) and make the Pointer 1404 | * point to the IPv6 Next Header field. 1405 | * 1406 | * Code 3 (Port Unreachable): Set the Code to 4 (Port 1407 | * unreachable). 1408 | * 1409 | * Code 4 (Fragmentation Needed and DF was Set): Translate to 1410 | * an ICMPv6 Packet Too Big message (Type 2) with Code set 1411 | * to 0. The MTU field MUST be adjusted for the difference 1412 | * between the IPv4 and IPv6 header sizes, i.e., 1413 | * minimum(advertised MTU+20, MTU_of_IPv6_nexthop, 1414 | * (MTU_of_IPv4_nexthop)+20). Note that if the IPv4 router 1415 | * set the MTU field to zero, i.e., the router does not 1416 | * implement [RFC1191], then the translator MUST use the 1417 | * plateau values specified in [RFC1191] to determine a 1418 | * likely path MTU and include that path MTU in the ICMPv6 1419 | * packet. (Use the greatest plateau value that is less 1420 | * than the returned Total Length field.) 1421 | * 1422 | * See also the requirements in Section 6. 1423 | * 1424 | * Code 5 (Source Route Failed): Set the Code to 0 (No route 1425 | * to destination). Note that this error is unlikely since 1426 | * source routes are not translated. 1427 | * 1428 | * Code 6, 7, 8: Set the Code to 0 (No route to destination). 1429 | * 1430 | * Code 9, 10 (Communication with Destination Host 1431 | * Administratively Prohibited): Set the Code to 1 1432 | * (Communication with destination administratively 1433 | * prohibited). 1434 | * 1435 | * Code 11, 12: Set the Code to 0 (No route to destination). 1436 | * 1437 | * Code 13 (Communication Administratively Prohibited): Set 1438 | * the Code to 1 (Communication with destination 1439 | * administratively prohibited). 1440 | * 1441 | * Code 14 (Host Precedence Violation): Silently drop. 1442 | * 1443 | * Code 15 (Precedence cutoff in effect): Set the Code to 1 1444 | * (Communication with destination administratively 1445 | * prohibited). 1446 | * 1447 | * Other Code values: Silently drop. 1448 | * 1449 | */ 1450 | 1451 | u16 *pmtu = ((u16 *)icmph) + 3; /* IPv4-compatible MTU value is 16 bit */ 1452 | 1453 | switch (icmph->code) { 1454 | case 0: 1455 | case 1: 1456 | icmph->code = 0; 1457 | break; 1458 | case 2: 1459 | /* FIXME: set ICMPv6 parameter pointer to 6 */ 1460 | icmph->type = 4; 1461 | icmph->code = 1; 1462 | break; 1463 | case 3: 1464 | icmph->code = 4; 1465 | break; 1466 | case 4: 1467 | /* 1468 | * On adjusting the signaled MTU within packet: 1469 | * 1470 | * IPv4 has 20 bytes smaller header size, so, standard says 1471 | * we can advertise a higher MTU here. However, then we will 1472 | * need to ensure it does not overshoot our egress link MTU, 1473 | * which implies knowing the egress interface, which is 1474 | * not trivial in the current model. 1475 | * 1476 | * So, we'd want to leave the MTU as aside. But, the Section 6 1477 | * has something more to say: 1478 | * 1479 | * 1. In the IPv4-to-IPv6 direction: if the MTU value of ICMPv4 Packet 1480 | * Too Big (PTB) messages is less than 1280, change it to 1280. 1481 | * This is intended to cause the IPv6 host and IPv6 firewall to 1482 | * process the ICMP PTB message and generate subsequent packets to 1483 | * this destination with an IPv6 Fragment Header. 1484 | * 1485 | */ 1486 | icmph->type = 2; 1487 | icmph->code = 0; 1488 | if (ntohs(*pmtu) < 1280) { 1489 | *pmtu = htons(1280); 1490 | } 1491 | break; 1492 | case 5: 1493 | case 6: 1494 | case 7: 1495 | case 8: 1496 | icmph->code = 0; 1497 | break; 1498 | case 9: 1499 | case 10: 1500 | icmph->code = 1; 1501 | break; 1502 | case 11: 1503 | case 12: 1504 | icmph->code = 0; 1505 | break; 1506 | case 13: 1507 | case 15: 1508 | icmph->code = 1; 1509 | break; 1510 | default: 1511 | iph->protocol = NEXTHDR_NONE; 1512 | } 1513 | return 0; 1514 | } 1515 | 1516 | 1517 | /* Fixup ICMP->ICMP6 before IP header translation, according to http://tools.ietf.org/html/rfc6145 */ 1518 | 1519 | static uint16_t nat46_fixup_icmp(nat46_instance_t *nat46, struct iphdr *iph, struct sk_buff *old_skb) { 1520 | struct icmphdr *icmph = (struct icmphdr *)(iph+1); 1521 | uint16_t ret = 0; 1522 | 1523 | iph->protocol = NEXTHDR_ICMP; 1524 | 1525 | switch(icmph->type) { 1526 | case ICMP_ECHO: 1527 | icmph->type = ICMPV6_ECHO_REQUEST; 1528 | ret = icmph->un.echo.id; 1529 | nat46debug(3, "ICMP echo request translated into IPv6, id: %d", ntohs(ret)); 1530 | break; 1531 | case ICMP_ECHOREPLY: 1532 | icmph->type = ICMPV6_ECHO_REPLY; 1533 | ret = icmph->un.echo.id; 1534 | nat46debug(3, "ICMP echo reply translated into IPv6, id: %d", ntohs(ret)); 1535 | break; 1536 | case ICMP_TIME_EXCEEDED: 1537 | ret = nat46_fixup_icmp_time_exceeded(nat46, iph, icmph, old_skb); 1538 | break; 1539 | case ICMP_PARAMETERPROB: 1540 | ret = nat46_fixup_icmp_parameterprob(nat46, iph, icmph, old_skb); 1541 | break; 1542 | case ICMP_DEST_UNREACH: 1543 | ret = nat46_fixup_icmp_dest_unreach(nat46, iph, icmph, old_skb); 1544 | break; 1545 | default: 1546 | /* Silently drop. */ 1547 | iph->protocol = NEXTHDR_NONE; 1548 | } 1549 | return ret; 1550 | } 1551 | 1552 | static int pairs_xlate_v6_to_v4_outer(nat46_instance_t *nat46, struct ipv6hdr *ip6h, uint16_t proto, __u32 *pv4saddr, __u32 *pv4daddr) { 1553 | int ipair = 0; 1554 | nat46_xlate_rulepair_t *apair = NULL; 1555 | int xlate_src = -1; 1556 | int xlate_dst = -1; 1557 | 1558 | for(ipair = 0; ipair < nat46->npairs; ipair++) { 1559 | apair = &nat46->pairs[ipair]; 1560 | 1561 | if(-1 == xlate_dst) { 1562 | if (xlate_v6_to_v4(nat46, &apair->local, &ip6h->daddr, pv4daddr)) { 1563 | xlate_dst = ipair; 1564 | } 1565 | } 1566 | if(-1 == xlate_src) { 1567 | if (xlate_v6_to_v4(nat46, &apair->remote, &ip6h->saddr, pv4saddr)) { 1568 | xlate_src = ipair; 1569 | } 1570 | } 1571 | if( (xlate_src >= 0) && (xlate_dst >= 0) ) { 1572 | break; 1573 | } else { 1574 | /* We did not match fully and there are more rules */ 1575 | if((ipair+1 < nat46->npairs) && is_last_pair_in_group(apair)) { 1576 | xlate_src = -1; 1577 | xlate_dst = -1; 1578 | } 1579 | } 1580 | } 1581 | if (xlate_dst >= 0) { 1582 | if (xlate_src < 0) { 1583 | if(proto == NEXTHDR_ICMP) { 1584 | nat46debug(1, "[nat46] Could not translate remote address v6->v4, ipair %d, for ICMP6 use dest addr", ipair); 1585 | *pv4saddr = *pv4daddr; 1586 | xlate_src = xlate_dst; 1587 | } else { 1588 | nat46debug(5, "[nat46] Could not translate remote address v6->v4, ipair %d", ipair); 1589 | } 1590 | } 1591 | } else { 1592 | nat46debug(1, "[nat46] Could not find a translation pair v6->v4 src %pI6c dst %pI6c", &ip6h->saddr, &ip6h->daddr); 1593 | } 1594 | nat46debug(5, "[nat46] pairs_xlate_v6_to_v4_outer result src %d dst %d", xlate_src, xlate_dst); 1595 | return ( (xlate_src >= 0) && (xlate_dst >= 0) ); 1596 | } 1597 | 1598 | 1599 | int nat46_ipv6_input(struct sk_buff *old_skb) { 1600 | struct ipv6hdr *ip6h = ipv6_hdr(old_skb); 1601 | nat46_instance_t *nat46 = get_nat46_instance(old_skb); 1602 | uint16_t proto; 1603 | uint16_t frag_off; 1604 | uint16_t frag_id; 1605 | 1606 | struct iphdr * iph; 1607 | __u32 v4saddr, v4daddr; 1608 | struct sk_buff * new_skb = 0; 1609 | int err = 0; 1610 | int truncSize = 0; 1611 | int tailTruncSize = 0; 1612 | int v6packet_l3size = sizeof(*ip6h); 1613 | int l3_infrag_payload_len = ntohs(ip6h->payload_len); 1614 | int check_for_l4 = 0; 1615 | 1616 | nat46debug(4, "nat46_ipv6_input packet"); 1617 | 1618 | if(ip6_input_not_interested(nat46, ip6h, old_skb)) { 1619 | nat46debug(1, "nat46_ipv6_input not interested"); 1620 | goto done; 1621 | } 1622 | nat46debug(5, "nat46_ipv6_input next hdr: %d, len: %d, is_fragment: %d", 1623 | ip6h->nexthdr, old_skb->len, ip6h->nexthdr == NEXTHDR_FRAGMENT); 1624 | proto = ip6h->nexthdr; 1625 | if (proto == NEXTHDR_FRAGMENT) { 1626 | struct frag_hdr *fh = (struct frag_hdr*)(ip6h + 1); 1627 | v6packet_l3size += sizeof(struct frag_hdr); 1628 | l3_infrag_payload_len -= sizeof(struct frag_hdr); 1629 | nat46debug(2, "Fragment ID: %08X", fh->identification); 1630 | nat46debug_dump(nat46, 6, fh, ntohs(ip6h->payload_len)); 1631 | 1632 | if(fh->frag_off == 0) { 1633 | /* Atomic fragment */ 1634 | proto = fh->nexthdr; 1635 | frag_off = 0; /* no DF bit */ 1636 | frag_id = fold_ipv6_frag_id(fh->identification); 1637 | nat46debug(2, "Atomic fragment"); 1638 | check_for_l4 = 1; 1639 | } else { 1640 | if (0 == (ntohs(fh->frag_off) & IP6_OFFSET)) { 1641 | /* First fragment. Pretend business as usual, but when creating IP, set the "MF" bit. */ 1642 | frag_off = htons(((ntohs(fh->frag_off) & 7) << 13) + (((ntohs(fh->frag_off) >> 3) & 0x1FFF))); 1643 | frag_id = fold_ipv6_frag_id(fh->identification); 1644 | /* ntohs(fh->frag_off) & IP6_MF */ 1645 | proto = fh->nexthdr; 1646 | check_for_l4 = 1; 1647 | nat46debug(2, "First fragment, frag_off: %04X, frag id: %04X orig frag_off: %04X", ntohs(frag_off), frag_id, ntohs(fh->frag_off)); 1648 | } else { 1649 | /* Not the first fragment - leave as is, allow to translate IPv6->IPv4 */ 1650 | proto = fh->nexthdr; 1651 | frag_off = htons(((ntohs(fh->frag_off) & 7) << 13) + (((ntohs(fh->frag_off) >> 3) & 0x1FFF))); 1652 | frag_id = fold_ipv6_frag_id(fh->identification); 1653 | nat46debug(2, "Not first fragment, frag_off: %04X, frag id: %04X orig frag_off: %04X", ntohs(frag_off), frag_id, ntohs(fh->frag_off)); 1654 | } 1655 | if (NEXTHDR_ICMP == proto) { 1656 | err = try_reassembly(old_skb); 1657 | if (err) { 1658 | goto done; 1659 | } 1660 | ip6h = ipv6_hdr(old_skb); 1661 | v6packet_l3size = sizeof(*ip6h); 1662 | l3_infrag_payload_len = ntohs(ip6h->payload_len); 1663 | frag_off = 0; /* no DF bit */ 1664 | check_for_l4 = 1; 1665 | } 1666 | } 1667 | } else { 1668 | frag_off = htons(IP_DF); 1669 | frag_id = get_next_ip_id(); 1670 | check_for_l4 = 1; 1671 | } 1672 | 1673 | if(!pairs_xlate_v6_to_v4_outer(nat46, ip6h, proto, &v4saddr, &v4daddr)) { 1674 | goto done; 1675 | } 1676 | 1677 | if (check_for_l4) { 1678 | switch(proto) { 1679 | /* CHECKSUMS UPDATE */ 1680 | case NEXTHDR_TCP: { 1681 | struct tcphdr *th = add_offset(ip6h, v6packet_l3size); 1682 | u16 sum1 = csum_ipv6_unmagic(nat46, &ip6h->saddr, &ip6h->daddr, l3_infrag_payload_len, NEXTHDR_TCP, th->check); 1683 | u16 sum2 = csum_tcpudp_remagic(v4saddr, v4daddr, l3_infrag_payload_len, NEXTHDR_TCP, sum1); 1684 | th->check = sum2; 1685 | break; 1686 | } 1687 | case NEXTHDR_UDP: { 1688 | struct udphdr *udp = add_offset(ip6h, v6packet_l3size); 1689 | u16 sum1, sum2; 1690 | if ((udp->check == 0) && zero_csum_pass) { 1691 | /* zero checksum and the config to pass it is set - do nothing with it */ 1692 | break; 1693 | } 1694 | sum1 = csum_ipv6_unmagic(nat46, &ip6h->saddr, &ip6h->daddr, l3_infrag_payload_len, NEXTHDR_UDP, udp->check); 1695 | sum2 = csum_tcpudp_remagic(v4saddr, v4daddr, l3_infrag_payload_len, NEXTHDR_UDP, sum1); 1696 | udp->check = sum2; 1697 | break; 1698 | } 1699 | case NEXTHDR_ICMP: { 1700 | struct icmp6hdr *icmp6h = add_offset(ip6h, v6packet_l3size); 1701 | u16 sum1 = csum_ipv6_unmagic(nat46, &ip6h->saddr, &ip6h->daddr, l3_infrag_payload_len, NEXTHDR_ICMP, icmp6h->icmp6_cksum); 1702 | icmp6h->icmp6_cksum = sum1; 1703 | nat46debug_dump(nat46, 10, icmp6h, l3_infrag_payload_len); 1704 | nat46_fixup_icmp6(nat46, ip6h, icmp6h, old_skb, &tailTruncSize); 1705 | proto = IPPROTO_ICMP; 1706 | break; 1707 | } 1708 | default: 1709 | break; 1710 | } 1711 | } else { 1712 | if(NEXTHDR_ICMP == proto) { 1713 | proto = IPPROTO_ICMP; 1714 | } 1715 | } 1716 | 1717 | new_skb = skb_copy(old_skb, GFP_ATOMIC); // other possible option: GFP_ATOMIC 1718 | if (!new_skb) { 1719 | nat46debug(0, "[nat46] Could not copy v6 skb"); 1720 | goto done; 1721 | } 1722 | 1723 | /* Remove any debris in the socket control block */ 1724 | memset(IPCB(new_skb), 0, sizeof(struct inet_skb_parm)); 1725 | /* Remove netfilter references to IPv6 packet, new netfilter references will be created based on IPv4 packet */ 1726 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) 1727 | nf_reset(new_skb); 1728 | #else 1729 | nf_reset_ct(new_skb); 1730 | #endif 1731 | 1732 | /* modify packet: actual IPv6->IPv4 transformation */ 1733 | truncSize = v6packet_l3size - sizeof(struct iphdr); /* chop first 20 bytes */ 1734 | skb_pull(new_skb, truncSize); 1735 | skb_put(new_skb, -tailTruncSize); 1736 | l3_infrag_payload_len -= tailTruncSize; 1737 | skb_reset_network_header(new_skb); 1738 | skb_set_transport_header(new_skb,IPV4HDRSIZE); /* transport (TCP/UDP/ICMP/...) header starts after 20 bytes */ 1739 | 1740 | /* build IPv4 header */ 1741 | iph = ip_hdr(new_skb); 1742 | fill_v4hdr_from_v6hdr(iph, ip6h, v4saddr, v4daddr, frag_id, frag_off, proto, l3_infrag_payload_len); 1743 | new_skb->protocol = htons(ETH_P_IP); 1744 | 1745 | if (ntohs(iph->tot_len) >= 2000) { 1746 | nat46debug(0, "Too big IP len: %d", ntohs(iph->tot_len)); 1747 | } 1748 | 1749 | nat46debug(5, "about to send v4 packet, flags: %02x", IPCB(new_skb)->flags); 1750 | nat46_netdev_count_xmit(new_skb, old_skb->dev); 1751 | netif_rx(new_skb); 1752 | 1753 | /* TBD: should copy be released here? */ 1754 | 1755 | done: 1756 | release_nat46_instance(nat46); 1757 | return err; 1758 | } 1759 | 1760 | 1761 | 1762 | static void ip6_update_csum(struct sk_buff * skb, struct ipv6hdr * ip6hdr, int do_atomic_frag) 1763 | { 1764 | u32 sum1=0; 1765 | u16 sum2=0; 1766 | __sum16 oldsum = 0; 1767 | 1768 | switch (ip6hdr->nexthdr) { 1769 | case IPPROTO_TCP: { 1770 | struct tcphdr *th = tcp_hdr(skb); 1771 | unsigned tcplen = 0; 1772 | 1773 | oldsum = th->check; 1774 | tcplen = ntohs(ip6hdr->payload_len) - (do_atomic_frag?8:0); /* TCP header + payload */ 1775 | th->check = 0; 1776 | sum1 = csum_partial((char*)th, tcplen, 0); /* calculate checksum for TCP hdr+payload */ 1777 | sum2 = csum_ipv6_magic(&ip6hdr->saddr, &ip6hdr->daddr, tcplen, ip6hdr->nexthdr, sum1); /* add pseudoheader */ 1778 | th->check = sum2; 1779 | break; 1780 | } 1781 | case IPPROTO_UDP: { 1782 | struct udphdr *udp = udp_hdr(skb); 1783 | unsigned udplen = ntohs(ip6hdr->payload_len) - (do_atomic_frag?8:0); /* UDP hdr + payload */ 1784 | 1785 | if ((udp->check == 0) && zero_csum_pass) { 1786 | /* zero checksum and the config to pass it is set - do nothing with it */ 1787 | break; 1788 | } 1789 | 1790 | oldsum = udp->check; 1791 | udp->check = 0; 1792 | 1793 | sum1 = csum_partial((char*)udp, udplen, 0); /* calculate checksum for UDP hdr+payload */ 1794 | sum2 = csum_ipv6_magic(&ip6hdr->saddr, &ip6hdr->daddr, udplen, ip6hdr->nexthdr, sum1); /* add pseudoheader */ 1795 | 1796 | udp->check = sum2; 1797 | 1798 | break; 1799 | } 1800 | case NEXTHDR_ICMP: { 1801 | struct icmp6hdr *icmp6h = icmp6_hdr(skb); 1802 | unsigned icmp6len = 0; 1803 | if (do_atomic_frag) { 1804 | break; 1805 | } 1806 | icmp6len = ntohs(ip6hdr->payload_len) - (do_atomic_frag?8:0); /* ICMP header + payload */ 1807 | icmp6h->icmp6_cksum = 0; 1808 | sum1 = csum_partial((char*)icmp6h, icmp6len, 0); /* calculate checksum for TCP hdr+payload */ 1809 | sum2 = csum_ipv6_magic(&ip6hdr->saddr, &ip6hdr->daddr, icmp6len, ip6hdr->nexthdr, sum1); /* add pseudoheader */ 1810 | icmp6h->icmp6_cksum = sum2; 1811 | break; 1812 | } 1813 | } 1814 | } 1815 | 1816 | static int ip4_input_not_interested(nat46_instance_t *nat46, struct iphdr *iph, struct sk_buff *old_skb) { 1817 | if (old_skb->protocol != htons(ETH_P_IP)) { 1818 | nat46debug(3, "Not an IPv4 packet"); 1819 | return 1; 1820 | } 1821 | // FIXME: check source to be within our prefix 1822 | return 0; 1823 | } 1824 | 1825 | static int pairs_xlate_v4_to_v6_outer(nat46_instance_t *nat46, struct iphdr *hdr4, uint16_t *sport, uint16_t *dport, void *v6saddr, void *v6daddr) { 1826 | int ipair = 0; 1827 | nat46_xlate_rulepair_t *apair = NULL; 1828 | int xlate_src = -1; 1829 | int xlate_dst = -1; 1830 | 1831 | for(ipair = 0; ipair < nat46->npairs; ipair++) { 1832 | apair = &nat46->pairs[ipair]; 1833 | 1834 | if(-1 == xlate_src) { 1835 | if(xlate_v4_to_v6(nat46, &apair->local, &hdr4->saddr, v6saddr, sport)) { 1836 | xlate_src = ipair; 1837 | } 1838 | } 1839 | if(-1 == xlate_dst) { 1840 | if(xlate_v4_to_v6(nat46, &apair->remote, &hdr4->daddr, v6daddr, dport)) { 1841 | xlate_dst = ipair; 1842 | } 1843 | } 1844 | if( (xlate_src >= 0) && (xlate_dst >= 0) ) { 1845 | break; 1846 | } else { 1847 | /* We did not match fully and there are more rules */ 1848 | if((ipair+1 < nat46->npairs) && is_last_pair_in_group(apair)) { 1849 | xlate_src = -1; 1850 | xlate_dst = -1; 1851 | } 1852 | } 1853 | } 1854 | nat46debug(5, "[nat46] pairs_xlate_v4_to_v6_outer result: src %d dst %d", xlate_src, xlate_dst); 1855 | if ( (xlate_src >= 0) && (xlate_dst >= 0) ) { 1856 | return 1; 1857 | } 1858 | 1859 | nat46debug(1, "[nat46] Could not find a translation pair v4->v6"); 1860 | 1861 | return 0; 1862 | } 1863 | 1864 | 1865 | int nat46_ipv4_input(struct sk_buff *old_skb) { 1866 | nat46_instance_t *nat46 = get_nat46_instance(old_skb); 1867 | struct sk_buff *new_skb; 1868 | uint16_t sport = 0, dport = 0; 1869 | 1870 | int err = 0; 1871 | int tclass = 0; 1872 | int flowlabel = 0; 1873 | int check_for_l4 = 0; 1874 | int having_l4 = 0; 1875 | int add_frag_header = 0; 1876 | 1877 | struct ipv6hdr * hdr6; 1878 | struct iphdr * hdr4 = ip_hdr(old_skb); 1879 | 1880 | char v6saddr[16], v6daddr[16]; 1881 | 1882 | memset(v6saddr, 1, 16); 1883 | memset(v6daddr, 2, 16); 1884 | 1885 | if (ip4_input_not_interested(nat46, hdr4, old_skb)) { 1886 | goto done; 1887 | } 1888 | nat46debug(1, "nat46_ipv4_input packet"); 1889 | nat46debug(5, "nat46_ipv4_input protocol: %d, len: %d, flags: %02x", hdr4->protocol, old_skb->len, IPCB(old_skb)->flags); 1890 | if(0 == (ntohs(hdr4->frag_off) & 0x3FFF) ) { 1891 | check_for_l4 = 1; 1892 | } else if (IPPROTO_ICMP == hdr4->protocol) { 1893 | /* 1894 | * receive fragmented ICMP: 1895 | * Need to reassemble it before processing. 1896 | */ 1897 | err = try_reassembly(old_skb); 1898 | if (err) { 1899 | goto done; 1900 | } 1901 | hdr4 = ip_hdr(old_skb); 1902 | check_for_l4 = 1; 1903 | } else { 1904 | add_frag_header = 1; 1905 | if (0 == (ntohs(hdr4->frag_off) & 0x1FFF)) { 1906 | check_for_l4 = 1; 1907 | } 1908 | } 1909 | 1910 | if (check_for_l4) { 1911 | switch(hdr4->protocol) { 1912 | case IPPROTO_TCP: { 1913 | struct tcphdr *th = tcp_hdr(old_skb); 1914 | sport = th->source; 1915 | dport = th->dest; 1916 | having_l4 = 1; 1917 | break; 1918 | } 1919 | case IPPROTO_UDP: { 1920 | struct udphdr *udp = udp_hdr(old_skb); 1921 | sport = udp->source; 1922 | dport = udp->dest; 1923 | having_l4 = 1; 1924 | break; 1925 | } 1926 | case IPPROTO_ICMP: 1927 | sport = dport = nat46_fixup_icmp(nat46, hdr4, old_skb); 1928 | having_l4 = 1; 1929 | break; 1930 | default: 1931 | break; 1932 | } 1933 | } else { 1934 | if (IPPROTO_ICMP == hdr4->protocol) { 1935 | /* should not happen, we reassemble at beginning */ 1936 | goto done; 1937 | } 1938 | dport = 0; 1939 | sport = 0; 1940 | having_l4 = 1; 1941 | } 1942 | 1943 | if(!pairs_xlate_v4_to_v6_outer(nat46, hdr4, having_l4 ? &sport : NULL, having_l4 ? &dport : NULL, v6saddr, v6daddr)) { 1944 | nat46debug(0, "[nat46] Could not translate v4->v6"); 1945 | goto done; 1946 | } 1947 | 1948 | new_skb = skb_copy(old_skb, GFP_ATOMIC); 1949 | if (!new_skb) { 1950 | nat46debug(0, "[nat46] Could not copy v4 skb"); 1951 | goto done; 1952 | } 1953 | 1954 | /* Remove any debris in the socket control block */ 1955 | memset(IP6CB(new_skb), 0, sizeof(struct inet6_skb_parm)); 1956 | /* Remove netfilter references to IPv4 packet, new netfilter references will be created based on IPv6 packet */ 1957 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) 1958 | nf_reset(new_skb); 1959 | #else 1960 | nf_reset_ct(new_skb); 1961 | #endif 1962 | 1963 | /* expand header (add 20 extra bytes at the beginning of sk_buff) */ 1964 | pskb_expand_head(new_skb, IPV6HDRSIZE - (hdr4->ihl << 2) + (add_frag_header?8:0), 0, GFP_ATOMIC); 1965 | 1966 | skb_push(new_skb, IPV6HDRSIZE - (hdr4->ihl << 2) + (add_frag_header?8:0)); /* push boundary by extra 20 bytes */ 1967 | 1968 | skb_reset_network_header(new_skb); 1969 | skb_set_transport_header(new_skb, IPV6HDRSIZE + (add_frag_header?8:0) ); /* transport (TCP/UDP/ICMP/...) header starts after 40 bytes */ 1970 | 1971 | hdr6 = ipv6_hdr(new_skb); 1972 | memset(hdr6, 0, sizeof(*hdr6) + (add_frag_header?8:0)); 1973 | 1974 | /* build IPv6 header */ 1975 | tclass = ip_tos_ignore ? 0 : hdr4->tos; /* traffic class */ 1976 | *(__be32 *)hdr6 = htonl(0x60000000 | (tclass << 20)) | flowlabel; /* version, priority, flowlabel */ 1977 | 1978 | /* IPv6 length is a payload length, IPv4 is hdr+payload */ 1979 | hdr6->payload_len = htons(ntohs(hdr4->tot_len) - (hdr4->ihl << 2) + (add_frag_header?8:0)); 1980 | hdr6->nexthdr = hdr4->protocol; 1981 | hdr6->hop_limit = hdr4->ttl; 1982 | memcpy(&hdr6->saddr, v6saddr, 16); 1983 | memcpy(&hdr6->daddr, v6daddr, 16); 1984 | 1985 | new_skb->protocol = htons(ETH_P_IPV6); 1986 | 1987 | if (add_frag_header) { 1988 | struct frag_hdr *fh = (struct frag_hdr*)(hdr6 + 1); 1989 | fh->frag_off = htons(((ntohs(hdr4->frag_off) >> 13) & 7) + ((ntohs(hdr4->frag_off) & 0x1FFF) << 3)); 1990 | fh->nexthdr = hdr4->protocol; 1991 | fh->identification = htonl(ntohs(hdr4->id)); 1992 | } 1993 | ip6_update_csum(new_skb, hdr6, add_frag_header); 1994 | 1995 | hdr6->nexthdr = add_frag_header ? NEXTHDR_FRAGMENT : hdr4->protocol; 1996 | 1997 | 1998 | // FIXME: check if you can not fit the packet into the cached MTU 1999 | // if (dst_mtu(skb_dst(new_skb))==0) { } 2000 | 2001 | nat46debug(5, "about to send v6 packet, flags: %02x", IP6CB(new_skb)->flags); 2002 | nat46_netdev_count_xmit(new_skb, old_skb->dev); 2003 | netif_rx(new_skb); 2004 | 2005 | done: 2006 | release_nat46_instance(nat46); 2007 | return err; 2008 | } 2009 | 2010 | 2011 | -------------------------------------------------------------------------------- /nat46/modules/nat46-core.h: -------------------------------------------------------------------------------- 1 | /* 2 | * NAT46 core definitions 3 | * 4 | * Copyright (c) 2013-2014 Andrew Yourtchenko 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | */ 16 | 17 | #ifndef __NAT46_CORE_H__ 18 | #define __NAT46_CORE_H__ 19 | 20 | #include "nat46-glue.h" 21 | 22 | // #define nat46debug(level, format, ...) debug(DBG_V6, level, format, __VA_ARGS__) 23 | // #define nat46debug(level, format, ...) 24 | #define nat46debug(level, format, ...) do { if(nat46->debug >= level) { printk(format "\n", ##__VA_ARGS__); } } while (0) 25 | 26 | #define IPV6HDRSIZE 40 27 | #define IPV4HDRSIZE 20 28 | #define IPV6V4HDRDELTA (IPV6HDRSIZE - IPV4HDRSIZE) 29 | 30 | /* 31 | * A generic v4<->v6 translation structure. 32 | * The currently supported translation styles: 33 | */ 34 | 35 | typedef enum { 36 | NAT46_XLATE_NONE = 0, 37 | NAT46_XLATE_MAP, 38 | NAT46_XLATE_MAP0, 39 | NAT46_XLATE_RFC6052 40 | } nat46_xlate_style_t; 41 | 42 | #define NAT46_SIGNATURE 0x544e3634 43 | #define FREED_NAT46_SIGNATURE 0xdead544e 44 | 45 | typedef struct { 46 | nat46_xlate_style_t style; 47 | struct in6_addr v6_pref; 48 | int v6_pref_len; 49 | u32 v4_pref; 50 | int v4_pref_len; 51 | int ea_len; 52 | int psid_offset; 53 | int fmr_flag; 54 | } nat46_xlate_rule_t; 55 | 56 | typedef struct { 57 | nat46_xlate_rule_t local; 58 | nat46_xlate_rule_t remote; 59 | } nat46_xlate_rulepair_t; 60 | 61 | typedef struct { 62 | u32 sig; /* nat46 signature */ 63 | int refcount; 64 | int debug; 65 | 66 | int npairs; 67 | nat46_xlate_rulepair_t pairs[0]; /* npairs */ 68 | } nat46_instance_t; 69 | 70 | int nat46_ipv6_input(struct sk_buff *old_skb); 71 | int nat46_ipv4_input(struct sk_buff *old_skb); 72 | 73 | int nat46_set_ipair_config(nat46_instance_t *nat46, int ipair, char *buf, int count); 74 | int nat46_set_config(nat46_instance_t *nat46, char *buf, int count); 75 | 76 | int nat46_get_ipair_config(nat46_instance_t *nat46, int ipair, char *buf, int count); 77 | int nat46_get_config(nat46_instance_t *nat46, char *buf, int count); 78 | 79 | char *get_next_arg(char **ptail); 80 | nat46_instance_t *get_nat46_instance(struct sk_buff *sk); 81 | 82 | nat46_instance_t *alloc_nat46_instance(int npairs, nat46_instance_t *old, int from_ipair, int to_ipair, int remove_ipair); 83 | void release_nat46_instance(nat46_instance_t *nat46); 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /nat46/modules/nat46-glue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * glue functions, candidates to go to -core 3 | * 4 | * Copyright (c) 2013-2014 Andrew Yourtchenko 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | */ 16 | 17 | 18 | #include "nat46-glue.h" 19 | #include "nat46-core.h" 20 | 21 | static DEFINE_MUTEX(ref_lock); 22 | static int is_valid_nat46(nat46_instance_t *nat46) { 23 | return (nat46 && (nat46->sig == NAT46_SIGNATURE)); 24 | } 25 | 26 | nat46_instance_t *alloc_nat46_instance(int npairs, nat46_instance_t *old, int from_ipair, int to_ipair, int remove_ipair) { 27 | nat46_instance_t *nat46 = kzalloc(sizeof(nat46_instance_t) + npairs*sizeof(nat46_xlate_rulepair_t), GFP_KERNEL); 28 | if (!nat46) { 29 | printk("[nat46] make_nat46_instance: can not alloc a nat46 instance with %d pairs\n", npairs); 30 | return NULL; 31 | } else { 32 | printk("[nat46] make_nat46_instance: allocated nat46 instance with %d pairs\n", npairs); 33 | } 34 | nat46->sig = NAT46_SIGNATURE; 35 | nat46->npairs = npairs; 36 | nat46->refcount = 1; /* The caller gets the reference */ 37 | if (old) { 38 | nat46->debug = old->debug; 39 | for(; (from_ipair >= 0) && (to_ipair >= 0) && 40 | (from_ipair < old->npairs) && (to_ipair < nat46->npairs); from_ipair++) { 41 | if (from_ipair != remove_ipair) { 42 | nat46->pairs[to_ipair] = old->pairs[from_ipair]; 43 | to_ipair++; 44 | } 45 | } 46 | } 47 | return nat46; 48 | } 49 | 50 | 51 | nat46_instance_t *get_nat46_instance(struct sk_buff *sk) { 52 | nat46_instance_t *nat46 = netdev_nat46_instance(sk->dev); 53 | mutex_lock(&ref_lock); 54 | if (is_valid_nat46(nat46)) { 55 | nat46->refcount++; 56 | mutex_unlock(&ref_lock); 57 | return nat46; 58 | } else { 59 | printk("[nat46] get_nat46_instance: Could not find a valid NAT46 instance!"); 60 | mutex_unlock(&ref_lock); 61 | return NULL; 62 | } 63 | } 64 | 65 | void release_nat46_instance(nat46_instance_t *nat46) { 66 | mutex_lock(&ref_lock); 67 | nat46->refcount--; 68 | if(0 == nat46->refcount) { 69 | printk("[nat46] release_nat46_instance: freeing nat46 instance with %d pairs\n", nat46->npairs); 70 | nat46->sig = FREED_NAT46_SIGNATURE; 71 | kfree(nat46); 72 | } 73 | mutex_unlock(&ref_lock); 74 | } 75 | -------------------------------------------------------------------------------- /nat46/modules/nat46-glue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Glue headers, not much here. 3 | * 4 | * Copyright (c) 2013-2014 Andrew Yourtchenko 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "nat46-netdev.h" 25 | 26 | 27 | #ifndef IP6_OFFSET 28 | #define IP6_OFFSET 0xFFF8 29 | #endif 30 | 31 | #define assert(x) printk("Assertion failed: %s", #x) 32 | 33 | -------------------------------------------------------------------------------- /nat46/modules/nat46-module.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * module-wide functions, mostly boilerplate 4 | * 5 | * Copyright (c) 2013-2014 Andrew Yourtchenko 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 9 | * as published by the Free Software Foundation 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | 33 | #include // for basic filesystem 34 | #include // for the proc filesystem 35 | #include // for sequence files 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include 45 | #include 46 | 47 | #include "nat46-core.h" 48 | #include "nat46-netdev.h" 49 | 50 | #define NAT46_PROC_NAME "nat46" 51 | #define NAT46_CONTROL_PROC_NAME "control" 52 | 53 | #ifndef NAT46_VERSION 54 | #define NAT46_VERSION __DATE__ " " __TIME__ 55 | #endif 56 | 57 | MODULE_LICENSE("GPL"); 58 | MODULE_AUTHOR("Andrew Yourtchenko "); 59 | MODULE_DESCRIPTION("NAT46 stateless translation"); 60 | 61 | int debug = 0; 62 | int zero_csum_pass = 0; 63 | int ip_tos_ignore = 0; 64 | 65 | module_param(debug, int, 0); 66 | MODULE_PARM_DESC(debug, "debugging messages level (default=0)"); 67 | 68 | module_param(zero_csum_pass, int, 0); 69 | MODULE_PARM_DESC(zero_csum_pass, "pass all-zero checksum unchanged (default=0)"); 70 | 71 | module_param(ip_tos_ignore, int, 0); 72 | MODULE_PARM_DESC(ip_tos_ignore, "ignore IPv4 TOS and set IPv6 traffic class to zero (default=0)"); 73 | 74 | static DEFINE_MUTEX(add_del_lock); 75 | 76 | struct nat46_nsdata { 77 | struct proc_dir_entry *proc_entry; 78 | struct proc_dir_entry *proc_parent; 79 | }; 80 | 81 | static unsigned int nat46_netid; 82 | 83 | 84 | static struct net *nat46_get_net(void) 85 | { 86 | struct task_struct *task = current; 87 | if (!task || !task->nsproxy || !task->nsproxy->net_ns) 88 | return NULL; 89 | 90 | return task->nsproxy->net_ns; 91 | } 92 | 93 | static int nat46_proc_show(struct seq_file *m, void *v) 94 | { 95 | struct net *net; 96 | 97 | net = (struct net *)m->private; 98 | nat64_show_all_configs(net, m); 99 | return 0; 100 | } 101 | 102 | static int nat46_proc_open(struct inode *inode, struct file *file) 103 | { 104 | struct net *net; 105 | 106 | net = nat46_get_net(); 107 | if (!net) 108 | return -EFAULT; 109 | 110 | return single_open(file, nat46_proc_show, net); 111 | } 112 | 113 | static char *get_devname(char **ptail) 114 | { 115 | const int maxlen = IFNAMSIZ-1; 116 | char *devname = get_next_arg(ptail); 117 | if(devname && (strlen(devname) > maxlen)) { 118 | printk(KERN_INFO "nat46: '%s' is " 119 | "longer than %d chars, truncating\n", devname, maxlen); 120 | devname[maxlen] = 0; 121 | } 122 | return devname; 123 | } 124 | 125 | static ssize_t nat46_proc_write(struct file *file, const char __user *buffer, 126 | size_t count, loff_t *ppos) 127 | { 128 | struct net *net; 129 | char *buf = NULL; 130 | char *tail = NULL; 131 | char *devname = NULL; 132 | char *arg_name = NULL; 133 | 134 | net = nat46_get_net(); 135 | if (!net) 136 | return -EFAULT; 137 | 138 | buf = kmalloc(sizeof(char) * (count + 1), GFP_KERNEL); 139 | if (!buf) 140 | return -ENOMEM; 141 | 142 | if (copy_from_user(buf, buffer, count)) { 143 | kfree(buf); 144 | return -EFAULT; 145 | } 146 | tail = buf; 147 | buf[count] = '\0'; 148 | if( (count > 0) && (buf[count-1] == '\n') ) { 149 | buf[count-1] = '\0'; 150 | } 151 | 152 | while (NULL != (arg_name = get_next_arg(&tail))) { 153 | if (0 == strcmp(arg_name, "add")) { 154 | devname = get_devname(&tail); 155 | printk(KERN_INFO "nat46: adding device (%s)\n", devname); 156 | mutex_lock(&add_del_lock); 157 | nat46_create(net, devname); 158 | mutex_unlock(&add_del_lock); 159 | } else if (0 == strcmp(arg_name, "del")) { 160 | devname = get_devname(&tail); 161 | printk(KERN_INFO "nat46: deleting device (%s)\n", devname); 162 | mutex_lock(&add_del_lock); 163 | nat46_destroy(net, devname); 164 | mutex_unlock(&add_del_lock); 165 | } else if (0 == strcmp(arg_name, "config")) { 166 | devname = get_devname(&tail); 167 | printk(KERN_INFO "nat46: configure device (%s) with '%s'\n", devname, tail); 168 | mutex_lock(&add_del_lock); 169 | nat46_configure(net, devname, tail); 170 | mutex_unlock(&add_del_lock); 171 | } else if (0 == strcmp(arg_name, "insert")) { 172 | devname = get_devname(&tail); 173 | printk(KERN_INFO "nat46: insert new rule into device (%s) with '%s'\n", devname, tail); 174 | mutex_lock(&add_del_lock); 175 | nat46_insert(net, devname, tail); 176 | mutex_unlock(&add_del_lock); 177 | } else if (0 == strcmp(arg_name, "remove")) { 178 | devname = get_devname(&tail); 179 | printk(KERN_INFO "nat46: remove a rule from the device (%s) with '%s'\n", devname, tail); 180 | mutex_lock(&add_del_lock); 181 | nat46_remove(net, devname, tail); 182 | mutex_unlock(&add_del_lock); 183 | } 184 | } 185 | 186 | kfree(buf); 187 | return count; 188 | } 189 | 190 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0) 191 | static const struct file_operations nat46_proc_fops = { 192 | .owner = THIS_MODULE, 193 | .open = nat46_proc_open, 194 | .read = seq_read, 195 | .llseek = seq_lseek, 196 | .release = single_release, 197 | .write = nat46_proc_write, 198 | }; 199 | #else 200 | static const struct proc_ops nat46_proc_fops = { 201 | .proc_open = nat46_proc_open, 202 | .proc_read = seq_read, 203 | .proc_lseek = seq_lseek, 204 | .proc_release = single_release, 205 | .proc_write = nat46_proc_write, 206 | }; 207 | #endif 208 | 209 | 210 | static int __net_init nat46_ns_init(struct net *net) 211 | { 212 | struct nat46_nsdata *nsdata; 213 | 214 | nsdata = net_generic(net, nat46_netid); 215 | nsdata->proc_parent = proc_mkdir(NAT46_PROC_NAME, net->proc_net); 216 | if (nsdata->proc_parent) { 217 | nsdata->proc_entry = proc_create(NAT46_CONTROL_PROC_NAME, 0644, nsdata->proc_parent, &nat46_proc_fops); 218 | if(!nsdata->proc_entry) { 219 | remove_proc_entry(NAT46_PROC_NAME, net->proc_net); 220 | nsdata->proc_parent = NULL; 221 | printk(KERN_INFO "Error creating proc entry"); 222 | return -ENOMEM; 223 | } 224 | } 225 | return 0; 226 | } 227 | 228 | static void __net_exit nat46_ns_exit(struct net *net) 229 | { 230 | struct nat46_nsdata *nsdata; 231 | 232 | nat46_destroy_all(net); 233 | 234 | nsdata = net_generic(net, nat46_netid); 235 | if (nsdata->proc_parent) { 236 | if (nsdata->proc_entry) { 237 | remove_proc_entry(NAT46_CONTROL_PROC_NAME, nsdata->proc_parent); 238 | } 239 | remove_proc_entry(NAT46_PROC_NAME, net->proc_net); 240 | } 241 | } 242 | 243 | static struct pernet_operations nat46_net_ops = { 244 | .init = nat46_ns_init, 245 | .exit = nat46_ns_exit, 246 | .id = &nat46_netid, 247 | .size = sizeof(struct nat46_nsdata), 248 | }; 249 | 250 | static int __init nat46_init(void) 251 | { 252 | int ret = 0; 253 | 254 | printk("nat46: module (version %s) loaded.\n", NAT46_VERSION); 255 | ret = register_pernet_subsys(&nat46_net_ops); 256 | if(ret) { 257 | goto error; 258 | } 259 | return 0; 260 | 261 | error: 262 | return ret; 263 | } 264 | 265 | static void __exit nat46_exit(void) 266 | { 267 | unregister_pernet_subsys(&nat46_net_ops); 268 | printk("nat46: module unloaded.\n"); 269 | } 270 | 271 | module_init(nat46_init); 272 | module_exit(nat46_exit); 273 | 274 | 275 | -------------------------------------------------------------------------------- /nat46/modules/nat46-module.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (c) 2013-2014 Andrew Yourtchenko 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 7 | * as published by the Free Software Foundation 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | */ 15 | 16 | extern int debug; 17 | extern int zero_csum_pass; 18 | extern int ip_tos_ignore; 19 | -------------------------------------------------------------------------------- /nat46/modules/nat46-netdev.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Network device related boilerplate functions 3 | * 4 | * Copyright (c) 2013-2014 Andrew Yourtchenko 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | */ 16 | 17 | 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "nat46-core.h" 28 | #include "nat46-module.h" 29 | 30 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(6,9,0) 31 | #define dev_lock_list() rcu_read_lock() 32 | #define dev_unlock_list() rcu_read_unlock() 33 | #else 34 | #define dev_lock_list() read_lock(&dev_base_lock) 35 | #define dev_unlock_list() read_unlock(&dev_base_lock) 36 | #endif 37 | 38 | #define NETDEV_DEFAULT_NAME "nat46." 39 | 40 | typedef struct { 41 | u32 sig; 42 | nat46_instance_t *nat46; 43 | } nat46_netdev_priv_t; 44 | 45 | static u8 netdev_count = 0; 46 | 47 | static int nat46_netdev_up(struct net_device *dev); 48 | static int nat46_netdev_down(struct net_device *dev); 49 | 50 | static netdev_tx_t nat46_netdev_xmit(struct sk_buff *skb, struct net_device *dev); 51 | 52 | 53 | static const struct net_device_ops nat46_netdev_ops = { 54 | .ndo_open = nat46_netdev_up, /* Called at ifconfig nat46 up */ 55 | .ndo_stop = nat46_netdev_down, /* Called at ifconfig nat46 down */ 56 | .ndo_start_xmit = nat46_netdev_xmit, /* REQUIRED, must return NETDEV_TX_OK */ 57 | }; 58 | 59 | static int nat46_netdev_up(struct net_device *dev) 60 | { 61 | netif_start_queue(dev); 62 | return 0; 63 | } 64 | 65 | static int nat46_netdev_down(struct net_device *dev) 66 | { 67 | netif_stop_queue(dev); 68 | return 0; 69 | } 70 | 71 | static netdev_tx_t nat46_netdev_xmit(struct sk_buff *skb, struct net_device *dev) 72 | { 73 | int ret = 0; 74 | 75 | dev->stats.rx_packets++; 76 | dev->stats.rx_bytes += skb->len; 77 | if(ETH_P_IP == ntohs(skb->protocol)) { 78 | ret = nat46_ipv4_input(skb); 79 | } 80 | if(ETH_P_IPV6 == ntohs(skb->protocol)) { 81 | ret = nat46_ipv6_input(skb); 82 | } 83 | if(0 == ret) { 84 | dev_kfree_skb_any(skb); 85 | } 86 | return NETDEV_TX_OK; 87 | } 88 | 89 | void nat46_netdev_count_xmit(struct sk_buff *skb, struct net_device *dev) { 90 | dev->stats.tx_packets++; 91 | dev->stats.tx_bytes += skb->len; 92 | } 93 | 94 | void *netdev_nat46_instance(struct net_device *dev) { 95 | nat46_netdev_priv_t *priv = netdev_priv(dev); 96 | return priv->nat46; 97 | } 98 | 99 | static void netdev_nat46_set_instance(struct net_device *dev, nat46_instance_t *new_nat46) { 100 | nat46_netdev_priv_t *priv = netdev_priv(dev); 101 | if(priv->nat46) { 102 | release_nat46_instance(priv->nat46); 103 | } 104 | priv->nat46 = new_nat46; 105 | } 106 | 107 | static void nat46_netdev_setup(struct net_device *dev) 108 | { 109 | nat46_netdev_priv_t *priv = netdev_priv(dev); 110 | nat46_instance_t *nat46 = alloc_nat46_instance(1, NULL, -1, -1, -1); 111 | 112 | memset(priv, 0, sizeof(*priv)); 113 | priv->sig = NAT46_DEVICE_SIGNATURE; 114 | priv->nat46 = nat46; 115 | 116 | dev->netdev_ops = &nat46_netdev_ops; 117 | dev->type = ARPHRD_NONE; 118 | dev->hard_header_len = 0; 119 | dev->addr_len = 0; 120 | dev->mtu = 16384; /* iptables does reassembly. Rather than using ETH_DATA_LEN, let's try to get as much mileage as we can with the Linux stack */ 121 | #if LINUX_VERSION_CODE < KERNEL_VERSION(6,12,0) 122 | dev->features = NETIF_F_NETNS_LOCAL; 123 | #elif LINUX_VERSION_CODE < KERNEL_VERSION(6,15,0) 124 | dev->netns_local = true; 125 | #else 126 | dev->netns_immutable = true; 127 | #endif 128 | dev->flags = IFF_NOARP | IFF_POINTOPOINT; 129 | } 130 | 131 | static int nat46_netdev_create(struct net *net, char *basename, struct net_device **dev) 132 | { 133 | int ret = 0; 134 | char *devname = NULL; 135 | int automatic_name = 0; 136 | 137 | if (basename && strcmp("", basename)) { 138 | devname = kmalloc(strlen(basename)+1, GFP_KERNEL); 139 | } else { 140 | devname = kmalloc(strlen(NETDEV_DEFAULT_NAME)+3+1, GFP_KERNEL); 141 | automatic_name = 1; 142 | } 143 | if (!devname) { 144 | printk("nat46: can not allocate memory to store device name.\n"); 145 | ret = -ENOMEM; 146 | goto err; 147 | } 148 | if (automatic_name) { 149 | snprintf(devname, strlen(NETDEV_DEFAULT_NAME)+3, "%s%d", NETDEV_DEFAULT_NAME, netdev_count); 150 | netdev_count++; 151 | } else { 152 | strcpy(devname, basename); 153 | } 154 | 155 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(3,17,0) 156 | *dev = alloc_netdev(sizeof(nat46_instance_t), devname, nat46_netdev_setup); 157 | #else 158 | *dev = alloc_netdev(sizeof(nat46_instance_t), devname, NET_NAME_UNKNOWN, nat46_netdev_setup); 159 | #endif 160 | if (!*dev) { 161 | printk("nat46: Unable to allocate nat46 device '%s'.\n", devname); 162 | ret = -ENOMEM; 163 | goto err_alloc_dev; 164 | } 165 | 166 | dev_net_set(*dev, net); 167 | ret = register_netdev(*dev); 168 | if(ret) { 169 | printk("nat46: Unable to register nat46 device.\n"); 170 | ret = -ENOMEM; 171 | goto err_register_dev; 172 | } 173 | 174 | printk("nat46: netdevice nat46 '%s' created successfully.\n", devname); 175 | kfree(devname); 176 | 177 | return 0; 178 | 179 | err_register_dev: 180 | free_netdev(*dev); 181 | err_alloc_dev: 182 | kfree(devname); 183 | err: 184 | return ret; 185 | } 186 | 187 | static void nat46_netdev_destroy(struct net_device *dev) 188 | { 189 | dev->flags &= ~IFF_UP; 190 | netif_stop_queue(dev); 191 | netdev_nat46_set_instance(dev, NULL); 192 | unregister_netdev(dev); 193 | free_netdev(dev); 194 | printk("nat46: Destroying nat46 device.\n"); 195 | } 196 | 197 | static int is_nat46(struct net_device *dev) { 198 | nat46_netdev_priv_t *priv = netdev_priv(dev); 199 | return (priv && (NAT46_DEVICE_SIGNATURE == priv->sig)); 200 | } 201 | 202 | static struct net_device *find_dev(struct net *net, char *name) { 203 | struct net_device *dev; 204 | struct net_device *out = NULL; 205 | 206 | if(!name) { 207 | return NULL; 208 | } 209 | 210 | dev_lock_list(); 211 | dev = first_net_device(net); 212 | while (dev) { 213 | if((0 == strcmp(dev->name, name)) && is_nat46(dev)) { 214 | if(debug) { 215 | printk(KERN_INFO "found [%s]\n", dev->name); 216 | } 217 | out = dev; 218 | break; 219 | } 220 | dev = next_net_device(dev); 221 | } 222 | dev_unlock_list(); 223 | return out; 224 | } 225 | 226 | int nat46_create(struct net *net, char *devname) { 227 | int ret = 0; 228 | struct net_device *dev = find_dev(net, devname); 229 | if (dev) { 230 | printk("Can not add: device '%s' already exists!\n", devname); 231 | return -1; 232 | } 233 | ret = nat46_netdev_create(net, devname, &dev); 234 | return ret; 235 | } 236 | 237 | int nat46_destroy(struct net *net, char *devname) { 238 | struct net_device *dev = find_dev(net, devname); 239 | if(dev) { 240 | printk("Destroying '%s'\n", devname); 241 | nat46_netdev_destroy(dev); 242 | return 0; 243 | } else { 244 | printk("Could not find device '%s'\n", devname); 245 | return -1; 246 | } 247 | } 248 | 249 | int nat46_insert(struct net *net, char *devname, char *buf) { 250 | struct net_device *dev = find_dev(net, devname); 251 | int ret = -1; 252 | if(dev) { 253 | nat46_instance_t *nat46 = netdev_nat46_instance(dev); 254 | nat46_instance_t *nat46_new = alloc_nat46_instance(nat46->npairs+1, nat46, 0, 1, -1); 255 | if(nat46_new) { 256 | netdev_nat46_set_instance(dev, nat46_new); 257 | ret = nat46_set_ipair_config(nat46_new, 0, buf, strlen(buf)); 258 | } else { 259 | printk("Could not insert a new rule on device %s\n", devname); 260 | } 261 | } 262 | return ret; 263 | } 264 | 265 | int nat46_configure(struct net *net, char *devname, char *buf) { 266 | struct net_device *dev = find_dev(net, devname); 267 | if(dev) { 268 | nat46_instance_t *nat46 = netdev_nat46_instance(dev); 269 | return nat46_set_config(nat46, buf, strlen(buf)); 270 | } else { 271 | return -1; 272 | } 273 | } 274 | 275 | int nat46_remove(struct net *net, char *devname, char *buf) { 276 | int ret = -1; 277 | char config_remove[NAT46_CFG_BUFLEN]; 278 | struct net_device *dev; 279 | nat46_instance_t *nat46; 280 | nat46_instance_t *nat46_remove; 281 | int result_rem; 282 | int i; 283 | 284 | if((dev = find_dev(net, devname)) == NULL || 285 | (nat46 = netdev_nat46_instance(dev)) == NULL || 286 | (nat46_remove = alloc_nat46_instance(1, NULL, -1, -1, -1)) == NULL) { 287 | return ret; 288 | } 289 | 290 | if(nat46_set_ipair_config(nat46_remove, 0, buf, NAT46_CFG_BUFLEN) < 0) { 291 | release_nat46_instance(nat46_remove); 292 | return ret; 293 | } 294 | 295 | result_rem = nat46_get_ipair_config(nat46_remove, 0, config_remove, NAT46_CFG_BUFLEN); 296 | for(i = 0; i < nat46->npairs; i++) { 297 | char config[NAT46_CFG_BUFLEN]; 298 | int result = nat46_get_ipair_config(nat46, i, config, NAT46_CFG_BUFLEN); 299 | 300 | if (result_rem == result && strncmp(config_remove, config, result_rem) == 0) { 301 | nat46_instance_t *nat46_new = alloc_nat46_instance(nat46->npairs-1, nat46, 0, 0, i); 302 | if(nat46_new) { 303 | netdev_nat46_set_instance(dev, nat46_new); 304 | ret = 0; 305 | } else { 306 | printk("Could not remove the rule from device %s\n", devname); 307 | } 308 | break; 309 | } 310 | } 311 | release_nat46_instance(nat46_remove); 312 | return ret; 313 | } 314 | 315 | void nat64_show_all_configs(struct net *net, struct seq_file *m) { 316 | struct net_device *dev; 317 | dev_lock_list(); 318 | dev = first_net_device(net); 319 | while (dev) { 320 | if(is_nat46(dev)) { 321 | nat46_instance_t *nat46 = netdev_nat46_instance(dev); 322 | int ipair = -1; 323 | char *buf = kmalloc(NAT46_CFG_BUFLEN + 1, GFP_KERNEL); 324 | seq_printf(m, "add %s\n", dev->name); 325 | if(buf) { 326 | for(ipair = 0; ipair < nat46->npairs; ipair++) { 327 | nat46_get_ipair_config(nat46, ipair, buf, NAT46_CFG_BUFLEN); 328 | if(ipair < nat46->npairs-1) { 329 | seq_printf(m,"insert %s %s\n", dev->name, buf); 330 | } else { 331 | seq_printf(m,"config %s %s\n", dev->name, buf); 332 | } 333 | } 334 | seq_printf(m,"\n"); 335 | kfree(buf); 336 | } 337 | } 338 | dev = next_net_device(dev); 339 | } 340 | dev_unlock_list(); 341 | 342 | } 343 | 344 | void nat46_destroy_all(struct net *net) { 345 | struct net_device *dev; 346 | struct net_device *nat46dev; 347 | do { 348 | dev_lock_list(); 349 | nat46dev = NULL; 350 | dev = first_net_device(net); 351 | while (dev) { 352 | if(is_nat46(dev)) { 353 | nat46dev = dev; 354 | } 355 | dev = next_net_device(dev); 356 | } 357 | dev_unlock_list(); 358 | if(nat46dev) { 359 | nat46_netdev_destroy(nat46dev); 360 | } 361 | } while (nat46dev); 362 | 363 | } 364 | -------------------------------------------------------------------------------- /nat46/modules/nat46-netdev.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (c) 2013-2014 Andrew Yourtchenko 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 7 | * as published by the Free Software Foundation 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | */ 15 | 16 | #define NAT46_DEVICE_SIGNATURE 0x544e36dd 17 | #define NAT46_CFG_BUFLEN 200 18 | 19 | int nat46_create(struct net *net, char *devname); 20 | int nat46_destroy(struct net *net, char *devname); 21 | int nat46_insert(struct net *net, char *devname, char *buf); 22 | int nat46_configure(struct net *net, char *devname, char *buf); 23 | int nat46_remove(struct net *net, char *devname, char *buf); 24 | void nat46_destroy_all(struct net *net); 25 | void nat64_show_all_configs(struct net *net, struct seq_file *m); 26 | void nat46_netdev_count_xmit(struct sk_buff *skb, struct net_device *dev); 27 | void *netdev_nat46_instance(struct net_device *dev); 28 | 29 | --------------------------------------------------------------------------------