diff options
author | Maciej Żenczykowski <maze@google.com> | 2023-09-12 11:41:26 -0700 |
---|---|---|
committer | Maciej Żenczykowski <maze@google.com> | 2023-09-12 11:41:28 -0700 |
commit | 036d5ddc4e264c79d2cc02d0d9152cb6af672563 (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 | |
parent | 20078300757aea3988fa8467649c19ae6d353af3 (diff) | |
download | android-clat-036d5ddc4e264c79d2cc02d0d9152cb6af672563.tar.gz |
delete all of external/android-clatd
being moved into packages/modules/Connectivity clatd
Test: N/A
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I15e1c0a2c7e1eef70b89de6a94bcdb508c852b38
-rw-r--r-- | .clang-format | 8 | ||||
-rw-r--r-- | Android.bp | 118 | ||||
-rw-r--r-- | BUGS | 5 | ||||
-rw-r--r-- | LICENSE | 201 | ||||
-rw-r--r-- | METADATA | 3 | ||||
-rw-r--r-- | MODULE_LICENSE_APACHE2 | 0 | ||||
-rw-r--r-- | NOTICE | 189 | ||||
-rw-r--r-- | OWNERS | 2 | ||||
-rw-r--r-- | PREUPLOAD.cfg | 5 | ||||
-rw-r--r-- | TEST_MAPPING | 10 | ||||
-rw-r--r-- | clatd.c | 307 | ||||
-rw-r--r-- | clatd.h | 81 | ||||
-rw-r--r-- | clatd_test.cpp | 835 | ||||
-rw-r--r-- | common.h | 40 | ||||
-rw-r--r-- | config.h | 48 | ||||
-rw-r--r-- | debug.h | 24 | ||||
-rw-r--r-- | dump.c | 250 | ||||
-rw-r--r-- | dump.h | 46 | ||||
-rw-r--r-- | icmp.c | 177 | ||||
-rw-r--r-- | icmp.h | 45 | ||||
-rw-r--r-- | ipv4.c | 146 | ||||
-rw-r--r-- | ipv6.c | 178 | ||||
-rw-r--r-- | logging.c | 55 | ||||
-rw-r--r-- | logging.h | 27 | ||||
-rw-r--r-- | main.c | 207 | ||||
-rw-r--r-- | translate.c | 529 | ||||
-rw-r--r-- | translate.h | 90 |
27 files changed, 0 insertions, 3626 deletions
diff --git a/.clang-format b/.clang-format deleted file mode 100644 index f1debbd..0000000 --- a/.clang-format +++ /dev/null @@ -1,8 +0,0 @@ -BasedOnStyle: Google -AlignConsecutiveAssignments: true -AlignEscapedNewlines: Right -ColumnLimit: 100 -CommentPragmas: NOLINT:.* -ContinuationIndentWidth: 2 -Cpp11BracedListStyle: false -TabWidth: 2 diff --git a/Android.bp b/Android.bp deleted file mode 100644 index 595c6b9..0000000 --- a/Android.bp +++ /dev/null @@ -1,118 +0,0 @@ -package { - default_applicable_licenses: ["external_android-clat_license"], -} - -// Added automatically by a large-scale-change -// -// large-scale-change included anything that looked like it might be a license -// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc. -// -// Please consider removing redundant or irrelevant files from 'license_text:'. -// See: http://go/android-license-faq -license { - name: "external_android-clat_license", - visibility: [":__subpackages__"], - license_kinds: [ - "SPDX-license-identifier-Apache-2.0", - ], - license_text: [ - "LICENSE", - "NOTICE", - ], -} - -cc_defaults { - name: "clatd_defaults", - - cflags: [ - "-Wall", - "-Werror", - "-Wunused-parameter", - - // Bug: http://b/33566695 - "-Wno-address-of-packed-member", - ], -} - -// Code used both by the daemon and by unit tests. -filegroup { - name: "clatd_common", - srcs: [ - "clatd.c", - "dump.c", - "icmp.c", - "ipv4.c", - "ipv6.c", - "logging.c", - "translate.c", - ], -} - -// The clat daemon. -cc_binary { - name: "clatd", - defaults: ["clatd_defaults"], - srcs: [ - ":clatd_common", - "main.c" - ], - static_libs: [ - "libip_checksum", - ], - shared_libs: [ - "liblog", - ], - relative_install_path: "for-system", - - // Static libc++ for smaller apex size while shipping clatd in the mainline module. - // See b/213123047 - stl: "libc++_static", - - // Only enable clang-tidy for the daemon, not the tests, because enabling it for the - // tests substantially increases build/compile cycle times and doesn't really provide a - // security benefit. - tidy: true, - tidy_checks: [ - "-*", - "cert-*", - "clang-analyzer-security*", - // b/2043314, warnings on memcpy_s, memset_s, snprintf_s calls - // are blocking the migration from gnu99 to gnu11. - // Until those warnings are fixed, disable these checks. - "-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling", - "android-*", - ], - tidy_checks_as_errors: [ - "clang-analyzer-security*", - "cert-*", - "android-*", - ], - - apex_available: [ - "com.android.tethering", - "//apex_available:platform", - ], - min_sdk_version: "30", -} - -// Unit tests. -cc_test { - name: "clatd_test", - defaults: ["clatd_defaults"], - srcs: [ - ":clatd_common", - "clatd_test.cpp" - ], - static_libs: [ - "libbase", - "libip_checksum", - "libnetd_test_tun_interface", - ], - shared_libs: [ - "libcutils", - "liblog", - "libnetutils", - ], - test_suites: ["device-tests"], - require_root: true, -} @@ -1,5 +0,0 @@ -known problems/assumptions: - - does not handle protocols other than ICMP, UDP, TCP and GRE/ESP - - assumes the handset has its own (routed) /64 ipv6 subnet - - assumes the /128 ipv6 subnet it generates can use the nat64 gateway - - assumes the nat64 gateway has the ipv4 address in the last 32 bits of the ipv6 address (that it uses a /96 plat subnet) diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/METADATA b/METADATA deleted file mode 100644 index d97975c..0000000 --- a/METADATA +++ /dev/null @@ -1,3 +0,0 @@ -third_party { - license_type: NOTICE -} diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2 deleted file mode 100644 index e69de29..0000000 --- a/MODULE_LICENSE_APACHE2 +++ /dev/null @@ -1,189 +0,0 @@ - Copyright (c) 2010-2012, Daniel Drown - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - @@ -1,2 +0,0 @@ -set noparent -file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg deleted file mode 100644 index c8dbf77..0000000 --- a/PREUPLOAD.cfg +++ /dev/null @@ -1,5 +0,0 @@ -[Builtin Hooks] -clang_format = true - -[Builtin Hooks Options] -clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp diff --git a/TEST_MAPPING b/TEST_MAPPING deleted file mode 100644 index d36908a..0000000 --- a/TEST_MAPPING +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presubmit": [ - { "name": "clatd_test" }, - { "name": "netd_integration_test" }, - { "name": "netd_unit_test" }, - { "name": "netdutils_test" }, - { "name": "resolv_integration_test" }, - { "name": "resolv_unit_test" } - ] -} diff --git a/clatd.c b/clatd.c deleted file mode 100644 index bac8b1d..0000000 --- a/clatd.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright 2012 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * clatd.c - tun interface setup and main event loop - */ -#include <arpa/inet.h> -#include <errno.h> -#include <fcntl.h> -#include <poll.h> -#include <signal.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/prctl.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <time.h> -#include <unistd.h> - -#include <linux/filter.h> -#include <linux/if.h> -#include <linux/if_ether.h> -#include <linux/if_packet.h> -#include <linux/if_tun.h> -#include <linux/virtio_net.h> -#include <net/if.h> -#include <sys/uio.h> - -#include "clatd.h" -#include "checksum.h" -#include "config.h" -#include "dump.h" -#include "logging.h" -#include "translate.h" - -struct clat_config Global_Clatd_Config; - -volatile sig_atomic_t running = 1; - -// reads IPv6 packet from AF_PACKET socket, translates to IPv4, writes to tun -void process_packet_6_to_4(struct tun_data *tunnel) { - // ethernet header is 14 bytes, plus 4 for a normal VLAN tag or 8 for Q-in-Q - // we don't really support vlans (or especially Q-in-Q)... - // but a few bytes of extra buffer space doesn't hurt... - struct { - struct virtio_net_hdr vnet; - uint8_t payload[22 + MAXMTU]; - char pad; // +1 to make packet truncation obvious - } buf; - struct iovec iov = { - .iov_base = &buf, - .iov_len = sizeof(buf), - }; - char cmsg_buf[CMSG_SPACE(sizeof(struct tpacket_auxdata))]; - struct msghdr msgh = { - .msg_iov = &iov, - .msg_iovlen = 1, - .msg_control = cmsg_buf, - .msg_controllen = sizeof(cmsg_buf), - }; - ssize_t readlen = recvmsg(tunnel->read_fd6, &msgh, /*flags*/ 0); - - if (readlen < 0) { - if (errno != EAGAIN) { - logmsg(ANDROID_LOG_WARN, "%s: read error: %s", __func__, strerror(errno)); - } - return; - } else if (readlen == 0) { - logmsg(ANDROID_LOG_WARN, "%s: packet socket removed?", __func__); - running = 0; - return; - } else if (readlen >= sizeof(buf)) { - logmsg(ANDROID_LOG_WARN, "%s: read truncation - ignoring pkt", __func__); - return; - } - - bool ok = false; - __u32 tp_status = 0; - __u16 tp_net = 0; - - for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)) { - if (cmsg->cmsg_level == SOL_PACKET && cmsg->cmsg_type == PACKET_AUXDATA) { - struct tpacket_auxdata *aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg); - ok = true; - tp_status = aux->tp_status; - tp_net = aux->tp_net; - break; - } - } - - if (!ok) { - // theoretically this should not happen... - static bool logged = false; - if (!logged) { - logmsg(ANDROID_LOG_ERROR, "%s: failed to fetch tpacket_auxdata cmsg", __func__); - logged = true; - } - } - - const int payload_offset = offsetof(typeof(buf), payload); - if (readlen < payload_offset + tp_net) { - logmsg(ANDROID_LOG_WARN, "%s: ignoring %zd byte pkt shorter than %d+%u L2 header", - __func__, readlen, payload_offset, tp_net); - return; - } - - const int pkt_len = readlen - payload_offset; - - // This will detect a skb->ip_summed == CHECKSUM_PARTIAL packet with non-final L4 checksum - if (tp_status & TP_STATUS_CSUMNOTREADY) { - static bool logged = false; - if (!logged) { - logmsg(ANDROID_LOG_WARN, "%s: L4 checksum calculation required", __func__); - logged = true; - } - - // These are non-negative by virtue of csum_start/offset being u16 - const int cs_start = buf.vnet.csum_start; - const int cs_offset = cs_start + buf.vnet.csum_offset; - if (cs_start > pkt_len) { - logmsg(ANDROID_LOG_ERROR, "%s: out of range - checksum start %d > %d", - __func__, cs_start, pkt_len); - } else if (cs_offset + 1 >= pkt_len) { - logmsg(ANDROID_LOG_ERROR, "%s: out of range - checksum offset %d + 1 >= %d", - __func__, cs_offset, pkt_len); - } else { - uint16_t csum = ip_checksum(buf.payload + cs_start, pkt_len - cs_start); - if (!csum) csum = 0xFFFF; // required fixup for UDP, TCP must live with it - buf.payload[cs_offset] = csum & 0xFF; - buf.payload[cs_offset + 1] = csum >> 8; - } - } - - translate_packet(tunnel->fd4, 0 /* to_ipv6 */, buf.payload + tp_net, pkt_len - tp_net); -} - -// reads TUN_PI + L3 IPv4 packet from tun, translates to IPv6, writes to AF_INET6/RAW socket -void process_packet_4_to_6(struct tun_data *tunnel) { - struct { - struct tun_pi pi; - uint8_t payload[MAXMTU]; - char pad; // +1 byte to make packet truncation obvious - } buf; - ssize_t readlen = read(tunnel->fd4, &buf, sizeof(buf)); - - if (readlen < 0) { - if (errno != EAGAIN) { - logmsg(ANDROID_LOG_WARN, "%s: read error: %s", __func__, strerror(errno)); - } - return; - } else if (readlen == 0) { - logmsg(ANDROID_LOG_WARN, "%s: tun interface removed", __func__); - running = 0; - return; - } else if (readlen >= sizeof(buf)) { - logmsg(ANDROID_LOG_WARN, "%s: read truncation - ignoring pkt", __func__); - return; - } - - const int payload_offset = offsetof(typeof(buf), payload); - - if (readlen < payload_offset) { - logmsg(ANDROID_LOG_WARN, "%s: short read: got %ld bytes", __func__, readlen); - return; - } - - const int pkt_len = readlen - payload_offset; - - uint16_t proto = ntohs(buf.pi.proto); - if (proto != ETH_P_IP) { - logmsg(ANDROID_LOG_WARN, "%s: unknown packet type = 0x%x", __func__, proto); - return; - } - - if (buf.pi.flags != 0) { - logmsg(ANDROID_LOG_WARN, "%s: unexpected flags = %d", __func__, buf.pi.flags); - } - - translate_packet(tunnel->write_fd6, 1 /* to_ipv6 */, buf.payload, pkt_len); -} - -// IPv6 DAD packet format: -// Ethernet header (if needed) will be added by the kernel: -// u8[6] src_mac; u8[6] dst_mac '33:33:ff:XX:XX:XX'; be16 ethertype '0x86DD' -// IPv6 header: -// be32 0x60000000 - ipv6, tclass 0, flowlabel 0 -// be16 payload_length '32'; u8 nxt_hdr ICMPv6 '58'; u8 hop limit '255' -// u128 src_ip6 '::' -// u128 dst_ip6 'ff02::1:ffXX:XXXX' -// ICMPv6 header: -// u8 type '135'; u8 code '0'; u16 icmp6 checksum; u32 reserved '0' -// ICMPv6 neighbour solicitation payload: -// u128 tgt_ip6 -// ICMPv6 ND options: -// u8 opt nr '14'; u8 length '1'; u8[6] nonce '6 random bytes' -void send_dad(int fd, const struct in6_addr* tgt) { - struct { - struct ip6_hdr ip6h; - struct nd_neighbor_solicit ns; - uint8_t ns_opt_nr; - uint8_t ns_opt_len; - uint8_t ns_opt_nonce[6]; - } dad_pkt = { - .ip6h = { - .ip6_flow = htonl(6 << 28), // v6, 0 tclass, 0 flowlabel - .ip6_plen = htons(sizeof(dad_pkt) - sizeof(struct ip6_hdr)), // payload length, ie. 32 - .ip6_nxt = IPPROTO_ICMPV6, // 58 - .ip6_hlim = 255, - .ip6_src = {}, // :: - .ip6_dst.s6_addr = { - 0xFF, 0x02, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 1, - 0xFF, tgt->s6_addr[13], tgt->s6_addr[14], tgt->s6_addr[15], - }, // ff02::1:ffXX:XXXX - multicast group address derived from bottom 24-bits of tgt - }, - .ns = { - .nd_ns_type = ND_NEIGHBOR_SOLICIT, // 135 - .nd_ns_code = 0, - .nd_ns_cksum = 0, // will be calculated later - .nd_ns_reserved = 0, - .nd_ns_target = *tgt, - }, - .ns_opt_nr = 14, // icmp6 option 'nonce' from RFC3971 - .ns_opt_len = 1, // in units of 8 bytes, including option nr and len - .ns_opt_nonce = {}, // opt_len *8 - sizeof u8(opt_nr) - sizeof u8(opt_len) = 6 ranodmized bytes - }; - arc4random_buf(&dad_pkt.ns_opt_nonce, sizeof(dad_pkt.ns_opt_nonce)); - - // 40 byte IPv6 header + 8 byte ICMPv6 header + 16 byte ipv6 target address + 8 byte nonce option - _Static_assert(sizeof(dad_pkt) == 40 + 8 + 16 + 8, "sizeof dad packet != 72"); - - // IPv6 header checksum is standard negated 16-bit one's complement sum over the icmpv6 pseudo - // header (which includes payload length, nextheader, and src/dst ip) and the icmpv6 payload. - // - // Src/dst ip immediately prefix the icmpv6 header itself, so can be handled along - // with the payload. We thus only need to manually account for payload len & next header. - // - // The magic '8' is simply the offset of the ip6_src field in the ipv6 header, - // ie. we're skipping over the ipv6 version, tclass, flowlabel, payload length, next header - // and hop limit fields, because they're not quite where we want them to be. - // - // ip6_plen is already in network order, while ip6_nxt is a single byte and thus needs htons(). - uint32_t csum = dad_pkt.ip6h.ip6_plen + htons(dad_pkt.ip6h.ip6_nxt); - csum = ip_checksum_add(csum, &dad_pkt.ip6h.ip6_src, sizeof(dad_pkt) - 8); - dad_pkt.ns.nd_ns_cksum = ip_checksum_finish(csum); - - const struct sockaddr_in6 dst = { - .sin6_family = AF_INET6, - .sin6_addr = dad_pkt.ip6h.ip6_dst, - .sin6_scope_id = if_nametoindex(Global_Clatd_Config.native_ipv6_interface), - }; - - sendto(fd, &dad_pkt, sizeof(dad_pkt), 0 /*flags*/, (const struct sockaddr *)&dst, sizeof(dst)); -} - -/* function: event_loop - * reads packets from the tun network interface and passes them down the stack - * tunnel - tun device data - */ -void event_loop(struct tun_data *tunnel) { - // Apparently some network gear will refuse to perform NS for IPs that aren't DAD'ed, - // this would then result in an ipv6-only network with working native ipv6, working - // IPv4 via DNS64, but non-functioning IPv4 via CLAT (ie. IPv4 literals + IPv4 only apps). - // The kernel itself doesn't do DAD for anycast ips (but does handle IPV6 MLD and handle ND). - // So we'll spoof dad here, and yeah, we really should check for a response and in - // case of failure pick a different IP. Seeing as 48-bits of the IP are utterly random - // (with the other 16 chosen to guarantee checksum neutrality) this seems like a remote - // concern... - // TODO: actually perform true DAD - send_dad(tunnel->write_fd6, &Global_Clatd_Config.ipv6_local_subnet); - - struct pollfd wait_fd[] = { - { tunnel->read_fd6, POLLIN, 0 }, - { tunnel->fd4, POLLIN, 0 }, - }; - - while (running) { - if (poll(wait_fd, ARRAY_SIZE(wait_fd), -1) == -1) { - if (errno != EINTR) { - logmsg(ANDROID_LOG_WARN, "event_loop/poll returned an error: %s", strerror(errno)); - } - } else { - // Call process_packet if the socket has data to be read, but also if an - // error is waiting. If we don't call read() after getting POLLERR, a - // subsequent poll() will return immediately with POLLERR again, - // causing this code to spin in a loop. Calling read() will clear the - // socket error flag instead. - if (wait_fd[0].revents) process_packet_6_to_4(tunnel); - if (wait_fd[1].revents) process_packet_4_to_6(tunnel); - } - } -} diff --git a/clatd.h b/clatd.h deleted file mode 100644 index e170c58..0000000 --- a/clatd.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2011 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * clatd.h - main routines used by clatd - */ -#ifndef __CLATD_H__ -#define __CLATD_H__ - -#include <signal.h> -#include <stdlib.h> -#include <sys/uio.h> - -struct tun_data; - -// IPv4 header has a u16 total length field, for maximum L3 mtu of 0xFFFF. -// -// Translating IPv4 to IPv6 requires removing the IPv4 header (20) and adding -// an IPv6 header (40), possibly with an extra ipv6 fragment extension header (8). -// -// As such the maximum IPv4 L3 mtu size is 0xFFFF (by u16 tot_len field) -// and the maximum IPv6 L3 mtu size is 0xFFFF + 28 (which is larger) -// -// A received non-jumbogram IPv6 frame could potentially be u16 payload_len = 0xFFFF -// + sizeof ipv6 header = 40, bytes in size. But such a packet cannot be meaningfully -// converted to IPv4 (it's too large). As such the restriction is the same: 0xFFFF + 28 -// -// (since there's no jumbogram support in IPv4, IPv6 jumbograms cannot be meaningfully -// converted to IPv4 anyway, and are thus entirely unsupported) -#define MAXMTU (0xFFFF + 28) - -// logcat_hexdump() maximum binary data length, this is the maximum packet size -// plus some extra space for various headers: -// struct tun_pi (4 bytes) -// struct virtio_net_hdr (10 bytes) -// ethernet (14 bytes), potentially including vlan tag (4) or tags (8 or 12) -// plus some extra just-in-case headroom, because it doesn't hurt. -#define MAXDUMPLEN (64 + MAXMTU) - -#define CLATD_VERSION "1.7" - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - -extern volatile sig_atomic_t running; - -void event_loop(struct tun_data *tunnel); - -/* function: parse_int - * parses a string as a decimal/hex/octal signed integer - * str - the string to parse - * out - the signed integer to write to, gets clobbered on failure - */ -static inline int parse_int(const char *str, int *out) { - char *end_ptr; - *out = strtol(str, &end_ptr, 0); - return *str && !*end_ptr; -} - -/* function: parse_unsigned - * parses a string as a decimal/hex/octal unsigned integer - * str - the string to parse - * out - the unsigned integer to write to, gets clobbered on failure - */ -static inline int parse_unsigned(const char *str, unsigned *out) { - char *end_ptr; - *out = strtoul(str, &end_ptr, 0); - return *str && !*end_ptr; -} - -#endif /* __CLATD_H__ */ diff --git a/clatd_test.cpp b/clatd_test.cpp deleted file mode 100644 index 0ed5f28..0000000 --- a/clatd_test.cpp +++ /dev/null @@ -1,835 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * clatd_test.cpp - unit tests for clatd - */ - -#include <iostream> - -#include <arpa/inet.h> -#include <linux/if_packet.h> -#include <netinet/in6.h> -#include <stdio.h> -#include <sys/uio.h> - -#include <gtest/gtest.h> - -#include "netutils/ifc.h" -#include "tun_interface.h" - -extern "C" { -#include "checksum.h" -#include "clatd.h" -#include "config.h" -#include "translate.h" -} - -// For convenience. -#define ARRAYSIZE(x) sizeof((x)) / sizeof((x)[0]) - -using android::net::TunInterface; - -// Default translation parameters. -static const char kIPv4LocalAddr[] = "192.0.0.4"; -static const char kIPv6LocalAddr[] = "2001:db8:0:b11::464"; -static const char kIPv6PlatSubnet[] = "64:ff9b::"; - -// clang-format off -// Test packet portions. Defined as macros because it's easy to concatenate them to make packets. -#define IPV4_HEADER(p, c1, c2) \ - 0x45, 0x00, 0, 41, /* Version=4, IHL=5, ToS=0x80, len=41 */ \ - 0x00, 0x00, 0x40, 0x00, /* ID=0x0000, flags=IP_DF, offset=0 */ \ - 55, (p), (c1), (c2), /* TTL=55, protocol=p, checksum=c1,c2 */ \ - 192, 0, 0, 4, /* Src=192.0.0.4 */ \ - 8, 8, 8, 8, /* Dst=8.8.8.8 */ -#define IPV4_UDP_HEADER IPV4_HEADER(IPPROTO_UDP, 0x73, 0xb0) -#define IPV4_ICMP_HEADER IPV4_HEADER(IPPROTO_ICMP, 0x73, 0xc0) - -#define IPV6_HEADER(p) \ - 0x60, 0x00, 0, 0, /* Version=6, tclass=0x00, flowlabel=0 */ \ - 0, 21, (p), 55, /* plen=11, nxthdr=p, hlim=55 */ \ - 0x20, 0x01, 0x0d, 0xb8, /* Src=2001:db8:0:b11::464 */ \ - 0x00, 0x00, 0x0b, 0x11, \ - 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x04, 0x64, \ - 0x00, 0x64, 0xff, 0x9b, /* Dst=64:ff9b::8.8.8.8 */ \ - 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, \ - 0x08, 0x08, 0x08, 0x08, -#define IPV6_UDP_HEADER IPV6_HEADER(IPPROTO_UDP) -#define IPV6_ICMPV6_HEADER IPV6_HEADER(IPPROTO_ICMPV6) - -#define UDP_LEN 21 -#define UDP_HEADER \ - 0xc8, 0x8b, 0, 53, /* Port 51339->53 */ \ - 0x00, UDP_LEN, 0, 0, /* Length 21, checksum empty for now */ - -#define PAYLOAD 'H', 'e', 'l', 'l', 'o', ' ', 0x4e, 0xb8, 0x96, 0xe7, 0x95, 0x8c, 0x00 - -#define IPV4_PING \ - 0x08, 0x00, 0x88, 0xd0, /* Type 8, code 0, checksum 0x88d0 */ \ - 0xd0, 0x0d, 0x00, 0x03, /* ID=0xd00d, seq=3 */ - -#define IPV6_PING \ - 0x80, 0x00, 0xc3, 0x42, /* Type 128, code 0, checksum 0xc342 */ \ - 0xd0, 0x0d, 0x00, 0x03, /* ID=0xd00d, seq=3 */ - -// Macros to return pseudo-headers from packets. -#define IPV4_PSEUDOHEADER(ip, tlen) \ - ip[12], ip[13], ip[14], ip[15], /* Source address */ \ - ip[16], ip[17], ip[18], ip[19], /* Destination address */ \ - 0, ip[9], /* 0, protocol */ \ - ((tlen) >> 16) & 0xff, (tlen) & 0xff, /* Transport length */ - -#define IPV6_PSEUDOHEADER(ip6, protocol, tlen) \ - ip6[8], ip6[9], ip6[10], ip6[11], /* Source address */ \ - ip6[12], ip6[13], ip6[14], ip6[15], \ - ip6[16], ip6[17], ip6[18], ip6[19], \ - ip6[20], ip6[21], ip6[22], ip6[23], \ - ip6[24], ip6[25], ip6[26], ip6[27], /* Destination address */ \ - ip6[28], ip6[29], ip6[30], ip6[31], \ - ip6[32], ip6[33], ip6[34], ip6[35], \ - ip6[36], ip6[37], ip6[38], ip6[39], \ - ((tlen) >> 24) & 0xff, /* Transport length */ \ - ((tlen) >> 16) & 0xff, \ - ((tlen) >> 8) & 0xff, \ - (tlen) & 0xff, \ - 0, 0, 0, (protocol), - -// A fragmented DNS request. -static const uint8_t kIPv4Frag1[] = { - 0x45, 0x00, 0x00, 0x24, 0xfe, 0x47, 0x20, 0x00, 0x40, 0x11, - 0x8c, 0x6d, 0xc0, 0x00, 0x00, 0x04, 0x08, 0x08, 0x08, 0x08, - 0x14, 0x5d, 0x00, 0x35, 0x00, 0x29, 0x68, 0xbb, 0x50, 0x47, - 0x01, 0x00, 0x00, 0x01, 0x00, 0x00 -}; -static const uint8_t kIPv4Frag2[] = { - 0x45, 0x00, 0x00, 0x24, 0xfe, 0x47, 0x20, 0x02, 0x40, 0x11, - 0x8c, 0x6b, 0xc0, 0x00, 0x00, 0x04, 0x08, 0x08, 0x08, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x69, 0x70, 0x76, 0x34, 0x06, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65 -}; -static const uint8_t kIPv4Frag3[] = { - 0x45, 0x00, 0x00, 0x1d, 0xfe, 0x47, 0x00, 0x04, 0x40, 0x11, - 0xac, 0x70, 0xc0, 0x00, 0x00, 0x04, 0x08, 0x08, 0x08, 0x08, - 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01 -}; -static const uint8_t *kIPv4Fragments[] = { kIPv4Frag1, kIPv4Frag2, kIPv4Frag3 }; -static const size_t kIPv4FragLengths[] = { sizeof(kIPv4Frag1), sizeof(kIPv4Frag2), - sizeof(kIPv4Frag3) }; - -static const uint8_t kIPv6Frag1[] = { - 0x60, 0x00, 0x00, 0x00, 0x00, 0x18, 0x2c, 0x40, 0x20, 0x01, - 0x0d, 0xb8, 0x00, 0x00, 0x0b, 0x11, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x64, 0x00, 0x64, 0xff, 0x9b, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, - 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0xfe, 0x47, 0x14, 0x5d, - 0x00, 0x35, 0x00, 0x29, 0xeb, 0x91, 0x50, 0x47, 0x01, 0x00, - 0x00, 0x01, 0x00, 0x00 -}; - -static const uint8_t kIPv6Frag2[] = { - 0x60, 0x00, 0x00, 0x00, 0x00, 0x18, 0x2c, 0x40, 0x20, 0x01, - 0x0d, 0xb8, 0x00, 0x00, 0x0b, 0x11, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x64, 0x00, 0x64, 0xff, 0x9b, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, - 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0xfe, 0x47, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x69, 0x70, 0x76, 0x34, 0x06, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65 -}; - -static const uint8_t kIPv6Frag3[] = { - 0x60, 0x00, 0x00, 0x00, 0x00, 0x11, 0x2c, 0x40, 0x20, 0x01, - 0x0d, 0xb8, 0x00, 0x00, 0x0b, 0x11, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x64, 0x00, 0x64, 0xff, 0x9b, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, - 0x11, 0x00, 0x00, 0x20, 0x00, 0x00, 0xfe, 0x47, 0x03, 0x63, - 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01 -}; -static const uint8_t *kIPv6Fragments[] = { kIPv6Frag1, kIPv6Frag2, kIPv6Frag3 }; -static const size_t kIPv6FragLengths[] = { sizeof(kIPv6Frag1), sizeof(kIPv6Frag2), - sizeof(kIPv6Frag3) }; - -static const uint8_t kReassembledIPv4[] = { - 0x45, 0x00, 0x00, 0x3d, 0xfe, 0x47, 0x00, 0x00, 0x40, 0x11, - 0xac, 0x54, 0xc0, 0x00, 0x00, 0x04, 0x08, 0x08, 0x08, 0x08, - 0x14, 0x5d, 0x00, 0x35, 0x00, 0x29, 0x68, 0xbb, 0x50, 0x47, - 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x69, 0x70, 0x76, 0x34, 0x06, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, - 0x01 -}; -// clang-format on - -// Expected checksums. -static const uint32_t kUdpPartialChecksum = 0xd5c8; -static const uint32_t kPayloadPartialChecksum = 0x31e9c; -static const uint16_t kUdpV4Checksum = 0xd0c7; -static const uint16_t kUdpV6Checksum = 0xa74a; - -uint8_t ip_version(const uint8_t *packet) { - uint8_t version = packet[0] >> 4; - return version; -} - -int is_ipv4_fragment(struct iphdr *ip) { - // A packet is a fragment if its fragment offset is nonzero or if the MF flag is set. - return ntohs(ip->frag_off) & (IP_OFFMASK | IP_MF); -} - -int is_ipv6_fragment(struct ip6_hdr *ip6, size_t len) { - if (ip6->ip6_nxt != IPPROTO_FRAGMENT) { - return 0; - } - struct ip6_frag *frag = (struct ip6_frag *)(ip6 + 1); - return len >= sizeof(*ip6) + sizeof(*frag) && - (frag->ip6f_offlg & (IP6F_OFF_MASK | IP6F_MORE_FRAG)); -} - -int ipv4_fragment_offset(struct iphdr *ip) { - return ntohs(ip->frag_off) & IP_OFFMASK; -} - -int ipv6_fragment_offset(struct ip6_frag *frag) { - return ntohs((frag->ip6f_offlg & IP6F_OFF_MASK) >> 3); -} - -void check_packet(const uint8_t *packet, size_t len, const char *msg) { - void *payload; - size_t payload_length = 0; - uint32_t pseudo_checksum = 0; - uint8_t protocol = 0; - int version = ip_version(packet); - switch (version) { - case 4: { - struct iphdr *ip = (struct iphdr *)packet; - ASSERT_GE(len, sizeof(*ip)) << msg << ": IPv4 packet shorter than IPv4 header\n"; - EXPECT_EQ(5, ip->ihl) << msg << ": Unsupported IP header length\n"; - EXPECT_EQ(len, ntohs(ip->tot_len)) << msg << ": Incorrect IPv4 length\n"; - EXPECT_EQ(0, ip_checksum(ip, sizeof(*ip))) << msg << ": Incorrect IP checksum\n"; - protocol = ip->protocol; - payload = ip + 1; - if (!is_ipv4_fragment(ip)) { - payload_length = len - sizeof(*ip); - pseudo_checksum = ipv4_pseudo_header_checksum(ip, payload_length); - } - ASSERT_TRUE(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP || protocol == IPPROTO_ICMP) - << msg << ": Unsupported IPv4 protocol " << protocol << "\n"; - break; - } - case 6: { - struct ip6_hdr *ip6 = (struct ip6_hdr *)packet; - ASSERT_GE(len, sizeof(*ip6)) << msg << ": IPv6 packet shorter than IPv6 header\n"; - EXPECT_EQ(len - sizeof(*ip6), htons(ip6->ip6_plen)) << msg << ": Incorrect IPv6 length\n"; - - if (ip6->ip6_nxt == IPPROTO_FRAGMENT) { - struct ip6_frag *frag = (struct ip6_frag *)(ip6 + 1); - ASSERT_GE(len, sizeof(*ip6) + sizeof(*frag)) - << msg << ": IPv6 fragment: short fragment header\n"; - protocol = frag->ip6f_nxt; - payload = frag + 1; - // Even though the packet has a Fragment header, it might not be a fragment. - if (!is_ipv6_fragment(ip6, len)) { - payload_length = len - sizeof(*ip6) - sizeof(*frag); - } - } else { - // Since there are no extension headers except Fragment, this must be the payload. - protocol = ip6->ip6_nxt; - payload = ip6 + 1; - payload_length = len - sizeof(*ip6); - } - ASSERT_TRUE(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP || protocol == IPPROTO_ICMPV6) - << msg << ": Unsupported IPv6 next header " << protocol; - if (payload_length) { - pseudo_checksum = ipv6_pseudo_header_checksum(ip6, payload_length, protocol); - } - break; - } - default: - FAIL() << msg << ": Unsupported IP version " << version << "\n"; - return; - } - - // If we understand the payload, verify the checksum. - if (payload_length) { - uint16_t checksum; - switch (protocol) { - case IPPROTO_UDP: - case IPPROTO_TCP: - case IPPROTO_ICMPV6: - checksum = ip_checksum_finish(ip_checksum_add(pseudo_checksum, payload, payload_length)); - break; - case IPPROTO_ICMP: - checksum = ip_checksum(payload, payload_length); - break; - default: - checksum = 0; // Don't check. - break; - } - EXPECT_EQ(0, checksum) << msg << ": Incorrect transport checksum\n"; - } - - if (protocol == IPPROTO_UDP) { - struct udphdr *udp = (struct udphdr *)payload; - EXPECT_NE(0, udp->check) << msg << ": UDP checksum 0 should be 0xffff"; - // If this is not a fragment, check the UDP length field. - if (payload_length) { - EXPECT_EQ(payload_length, ntohs(udp->len)) << msg << ": Incorrect UDP length\n"; - } - } -} - -void reassemble_packet(const uint8_t **fragments, const size_t lengths[], int numpackets, - uint8_t *reassembled, size_t *reassembled_len, const char *msg) { - struct iphdr *ip = nullptr; - struct ip6_hdr *ip6 = nullptr; - size_t total_length, pos = 0; - uint8_t protocol = 0; - uint8_t version = ip_version(fragments[0]); - - for (int i = 0; i < numpackets; i++) { - const uint8_t *packet = fragments[i]; - int len = lengths[i]; - int headersize, payload_offset; - - ASSERT_EQ(ip_version(packet), version) << msg << ": Inconsistent fragment versions\n"; - check_packet(packet, len, "Fragment sanity check"); - - switch (version) { - case 4: { - struct iphdr *ip_orig = (struct iphdr *)packet; - headersize = sizeof(*ip_orig); - ASSERT_TRUE(is_ipv4_fragment(ip_orig)) - << msg << ": IPv4 fragment #" << i + 1 << " not a fragment\n"; - ASSERT_EQ(pos, ipv4_fragment_offset(ip_orig) * 8 + ((i != 0) ? sizeof(*ip) : 0)) - << msg << ": IPv4 fragment #" << i + 1 << ": inconsistent offset\n"; - - headersize = sizeof(*ip_orig); - payload_offset = headersize; - if (pos == 0) { - ip = (struct iphdr *)reassembled; - } - break; - } - case 6: { - struct ip6_hdr *ip6_orig = (struct ip6_hdr *)packet; - struct ip6_frag *frag = (struct ip6_frag *)(ip6_orig + 1); - ASSERT_TRUE(is_ipv6_fragment(ip6_orig, len)) - << msg << ": IPv6 fragment #" << i + 1 << " not a fragment\n"; - ASSERT_EQ(pos, ipv6_fragment_offset(frag) * 8 + ((i != 0) ? sizeof(*ip6) : 0)) - << msg << ": IPv6 fragment #" << i + 1 << ": inconsistent offset\n"; - - headersize = sizeof(*ip6_orig); - payload_offset = sizeof(*ip6_orig) + sizeof(*frag); - if (pos == 0) { - ip6 = (struct ip6_hdr *)reassembled; - protocol = frag->ip6f_nxt; - } - break; - } - default: - FAIL() << msg << ": Invalid IP version << " << version; - } - - // If this is the first fragment, copy the header. - if (pos == 0) { - ASSERT_LT(headersize, (int)*reassembled_len) << msg << ": Reassembly buffer too small\n"; - memcpy(reassembled, packet, headersize); - total_length = headersize; - pos += headersize; - } - - // Copy the payload. - int payload_length = len - payload_offset; - total_length += payload_length; - ASSERT_LT(total_length, *reassembled_len) << msg << ": Reassembly buffer too small\n"; - memcpy(reassembled + pos, packet + payload_offset, payload_length); - pos += payload_length; - } - - // Fix up the reassembled headers to reflect fragmentation and length (and IPv4 checksum). - ASSERT_EQ(total_length, pos) << msg << ": Reassembled packet length incorrect\n"; - if (ip) { - ip->frag_off &= ~htons(IP_MF); - ip->tot_len = htons(total_length); - ip->check = 0; - ip->check = ip_checksum(ip, sizeof(*ip)); - ASSERT_FALSE(is_ipv4_fragment(ip)) << msg << ": reassembled IPv4 packet is a fragment!\n"; - } - if (ip6) { - ip6->ip6_nxt = protocol; - ip6->ip6_plen = htons(total_length - sizeof(*ip6)); - ASSERT_FALSE(is_ipv6_fragment(ip6, ip6->ip6_plen)) - << msg << ": reassembled IPv6 packet is a fragment!\n"; - } - - *reassembled_len = total_length; -} - -void check_data_matches(const void *expected, const void *actual, size_t len, const char *msg) { - if (memcmp(expected, actual, len)) { - // Hex dump, 20 bytes per line, one space between bytes (1 byte = 3 chars), indented by 4. - int hexdump_len = len * 3 + (len / 20 + 1) * 5; - char expected_hexdump[hexdump_len], actual_hexdump[hexdump_len]; - unsigned pos = 0; - for (unsigned i = 0; i < len; i++) { - if (i % 20 == 0) { - snprintf(expected_hexdump + pos, hexdump_len - pos, "\n "); - snprintf(actual_hexdump + pos, hexdump_len - pos, "\n "); - pos += 4; - } - snprintf(expected_hexdump + pos, hexdump_len - pos, " %02x", ((uint8_t *)expected)[i]); - snprintf(actual_hexdump + pos, hexdump_len - pos, " %02x", ((uint8_t *)actual)[i]); - pos += 3; - } - FAIL() << msg << ": Data doesn't match" - << "\n Expected:" << (char *) expected_hexdump - << "\n Actual:" << (char *) actual_hexdump << "\n"; - } -} - -void fix_udp_checksum(uint8_t *packet) { - uint32_t pseudo_checksum; - uint8_t version = ip_version(packet); - struct udphdr *udp; - switch (version) { - case 4: { - struct iphdr *ip = (struct iphdr *)packet; - udp = (struct udphdr *)(ip + 1); - pseudo_checksum = ipv4_pseudo_header_checksum(ip, ntohs(udp->len)); - break; - } - case 6: { - struct ip6_hdr *ip6 = (struct ip6_hdr *)packet; - udp = (struct udphdr *)(ip6 + 1); - pseudo_checksum = ipv6_pseudo_header_checksum(ip6, ntohs(udp->len), IPPROTO_UDP); - break; - } - default: - FAIL() << "unsupported IP version" << version << "\n"; - return; - } - - udp->check = 0; - udp->check = ip_checksum_finish(ip_checksum_add(pseudo_checksum, udp, ntohs(udp->len))); -} - -// Testing stub for send_rawv6. The real version uses sendmsg() with a -// destination IPv6 address, and attempting to call that on our test socketpair -// fd results in EINVAL. -extern "C" void send_rawv6(int fd, clat_packet out, int iov_len) { writev(fd, out, iov_len); } - -void do_translate_packet(const uint8_t *original, size_t original_len, uint8_t *out, size_t *outlen, - const char *msg) { - int fds[2]; - if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, fds)) { - abort(); - } - - char foo[512]; - snprintf(foo, sizeof(foo), "%s: Invalid original packet", msg); - check_packet(original, original_len, foo); - - int read_fd, write_fd; - uint16_t expected_proto; - int version = ip_version(original); - switch (version) { - case 4: - expected_proto = htons(ETH_P_IPV6); - read_fd = fds[1]; - write_fd = fds[0]; - break; - case 6: - expected_proto = htons(ETH_P_IP); - read_fd = fds[0]; - write_fd = fds[1]; - break; - default: - FAIL() << msg << ": Unsupported IP version " << version << "\n"; - break; - } - - translate_packet(write_fd, (version == 4), original, original_len); - - snprintf(foo, sizeof(foo), "%s: Invalid translated packet", msg); - if (version == 6) { - // Translating to IPv4. Expect a tun header. - struct tun_pi new_tun_header; - struct iovec iov[] = { - { &new_tun_header, sizeof(new_tun_header) }, - { out, *outlen }, - }; - - int len = readv(read_fd, iov, 2); - if (len > (int)sizeof(new_tun_header)) { - ASSERT_LT((size_t)len, *outlen) << msg << ": Translated packet buffer too small\n"; - EXPECT_EQ(expected_proto, new_tun_header.proto) << msg << "Unexpected tun proto\n"; - *outlen = len - sizeof(new_tun_header); - check_packet(out, *outlen, msg); - } else { - FAIL() << msg << ": Packet was not translated: len=" << len; - *outlen = 0; - } - } else { - // Translating to IPv6. Expect raw packet. - *outlen = read(read_fd, out, *outlen); - check_packet(out, *outlen, msg); - } -} - -void check_translated_packet(const uint8_t *original, size_t original_len, const uint8_t *expected, - size_t expected_len, const char *msg) { - uint8_t translated[MAXMTU]; - size_t translated_len = sizeof(translated); - do_translate_packet(original, original_len, translated, &translated_len, msg); - EXPECT_EQ(expected_len, translated_len) << msg << ": Translated packet length incorrect\n"; - check_data_matches(expected, translated, translated_len, msg); -} - -void check_fragment_translation(const uint8_t *original[], const size_t original_lengths[], - const uint8_t *expected[], const size_t expected_lengths[], - int numfragments, const char *msg) { - for (int i = 0; i < numfragments; i++) { - // Check that each of the fragments translates as expected. - char frag_msg[512]; - snprintf(frag_msg, sizeof(frag_msg), "%s: fragment #%d", msg, i + 1); - check_translated_packet(original[i], original_lengths[i], expected[i], expected_lengths[i], - frag_msg); - } - - // Sanity check that reassembling the original and translated fragments produces valid packets. - uint8_t reassembled[MAXMTU]; - size_t reassembled_len = sizeof(reassembled); - reassemble_packet(original, original_lengths, numfragments, reassembled, &reassembled_len, msg); - check_packet(reassembled, reassembled_len, msg); - - uint8_t translated[MAXMTU]; - size_t translated_len = sizeof(translated); - do_translate_packet(reassembled, reassembled_len, translated, &translated_len, msg); - check_packet(translated, translated_len, msg); -} - -int get_transport_checksum(const uint8_t *packet) { - struct iphdr *ip; - struct ip6_hdr *ip6; - uint8_t protocol; - const void *payload; - - int version = ip_version(packet); - switch (version) { - case 4: - ip = (struct iphdr *)packet; - if (is_ipv4_fragment(ip)) { - return -1; - } - protocol = ip->protocol; - payload = ip + 1; - break; - case 6: - ip6 = (struct ip6_hdr *)packet; - protocol = ip6->ip6_nxt; - payload = ip6 + 1; - break; - default: - return -1; - } - - switch (protocol) { - case IPPROTO_UDP: - return ((struct udphdr *)payload)->check; - - case IPPROTO_TCP: - return ((struct tcphdr *)payload)->check; - - case IPPROTO_FRAGMENT: - default: - return -1; - } -} - -class ClatdTest : public ::testing::Test { - protected: - static TunInterface sTun; - - virtual void SetUp() { - inet_pton(AF_INET, kIPv4LocalAddr, &Global_Clatd_Config.ipv4_local_subnet); - inet_pton(AF_INET6, kIPv6PlatSubnet, &Global_Clatd_Config.plat_subnet); - memset(&Global_Clatd_Config.ipv6_local_subnet, 0, sizeof(in6_addr)); - Global_Clatd_Config.native_ipv6_interface = const_cast<char *>(sTun.name().c_str()); - } - - // Static because setting up the tun interface takes about 40ms. - static void SetUpTestCase() { ASSERT_EQ(0, sTun.init()); } - - // Closing the socket removes the interface and IP addresses. - static void TearDownTestCase() { sTun.destroy(); } -}; - -TunInterface ClatdTest::sTun; - -void expect_ipv6_addr_equal(struct in6_addr *expected, struct in6_addr *actual) { - if (!IN6_ARE_ADDR_EQUAL(expected, actual)) { - char expected_str[INET6_ADDRSTRLEN], actual_str[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, expected, expected_str, sizeof(expected_str)); - inet_ntop(AF_INET6, actual, actual_str, sizeof(actual_str)); - FAIL() - << "Unexpected IPv6 address:: " - << "\n Expected: " << expected_str - << "\n Actual: " << actual_str - << "\n"; - } -} - -TEST_F(ClatdTest, TestIPv6PrefixEqual) { - EXPECT_TRUE(ipv6_prefix_equal(&Global_Clatd_Config.plat_subnet, - &Global_Clatd_Config.plat_subnet)); - EXPECT_FALSE(ipv6_prefix_equal(&Global_Clatd_Config.plat_subnet, - &Global_Clatd_Config.ipv6_local_subnet)); - - struct in6_addr subnet2 = Global_Clatd_Config.ipv6_local_subnet; - EXPECT_TRUE(ipv6_prefix_equal(&Global_Clatd_Config.ipv6_local_subnet, &subnet2)); - EXPECT_TRUE(ipv6_prefix_equal(&subnet2, &Global_Clatd_Config.ipv6_local_subnet)); - - subnet2.s6_addr[6] = 0xff; - EXPECT_FALSE(ipv6_prefix_equal(&Global_Clatd_Config.ipv6_local_subnet, &subnet2)); - EXPECT_FALSE(ipv6_prefix_equal(&subnet2, &Global_Clatd_Config.ipv6_local_subnet)); -} - -TEST_F(ClatdTest, DataSanitycheck) { - // Sanity checks the data. - uint8_t v4_header[] = { IPV4_UDP_HEADER }; - ASSERT_EQ(sizeof(struct iphdr), sizeof(v4_header)) << "Test IPv4 header: incorrect length\n"; - - uint8_t v6_header[] = { IPV6_UDP_HEADER }; - ASSERT_EQ(sizeof(struct ip6_hdr), sizeof(v6_header)) << "Test IPv6 header: incorrect length\n"; - - uint8_t udp_header[] = { UDP_HEADER }; - ASSERT_EQ(sizeof(struct udphdr), sizeof(udp_header)) << "Test UDP header: incorrect length\n"; - - // Sanity checks check_packet. - struct udphdr *udp; - uint8_t v4_udp_packet[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD }; - udp = (struct udphdr *)(v4_udp_packet + sizeof(struct iphdr)); - fix_udp_checksum(v4_udp_packet); - ASSERT_EQ(kUdpV4Checksum, udp->check) << "UDP/IPv4 packet checksum sanity check\n"; - check_packet(v4_udp_packet, sizeof(v4_udp_packet), "UDP/IPv4 packet sanity check"); - - uint8_t v6_udp_packet[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD }; - udp = (struct udphdr *)(v6_udp_packet + sizeof(struct ip6_hdr)); - fix_udp_checksum(v6_udp_packet); - ASSERT_EQ(kUdpV6Checksum, udp->check) << "UDP/IPv6 packet checksum sanity check\n"; - check_packet(v6_udp_packet, sizeof(v6_udp_packet), "UDP/IPv6 packet sanity check"); - - uint8_t ipv4_ping[] = { IPV4_ICMP_HEADER IPV4_PING PAYLOAD }; - check_packet(ipv4_ping, sizeof(ipv4_ping), "IPv4 ping sanity check"); - - uint8_t ipv6_ping[] = { IPV6_ICMPV6_HEADER IPV6_PING PAYLOAD }; - check_packet(ipv6_ping, sizeof(ipv6_ping), "IPv6 ping sanity check"); - - // Sanity checks reassemble_packet. - uint8_t reassembled[MAXMTU]; - size_t total_length = sizeof(reassembled); - reassemble_packet(kIPv4Fragments, kIPv4FragLengths, ARRAYSIZE(kIPv4Fragments), reassembled, - &total_length, "Reassembly sanity check"); - check_packet(reassembled, total_length, "IPv4 Reassembled packet is valid"); - ASSERT_EQ(sizeof(kReassembledIPv4), total_length) << "IPv4 reassembly sanity check: length\n"; - ASSERT_TRUE(!is_ipv4_fragment((struct iphdr *)reassembled)) - << "Sanity check: reassembled packet is a fragment!\n"; - check_data_matches(kReassembledIPv4, reassembled, total_length, "IPv4 reassembly sanity check"); - - total_length = sizeof(reassembled); - reassemble_packet(kIPv6Fragments, kIPv6FragLengths, ARRAYSIZE(kIPv6Fragments), reassembled, - &total_length, "IPv6 reassembly sanity check"); - ASSERT_TRUE(!is_ipv6_fragment((struct ip6_hdr *)reassembled, total_length)) - << "Sanity check: reassembled packet is a fragment!\n"; - check_packet(reassembled, total_length, "IPv6 Reassembled packet is valid"); -} - -TEST_F(ClatdTest, PseudoChecksum) { - uint32_t pseudo_checksum; - - uint8_t v4_header[] = { IPV4_UDP_HEADER }; - uint8_t v4_pseudo_header[] = { IPV4_PSEUDOHEADER(v4_header, UDP_LEN) }; - pseudo_checksum = ipv4_pseudo_header_checksum((struct iphdr *)v4_header, UDP_LEN); - EXPECT_EQ(ip_checksum_finish(pseudo_checksum), - ip_checksum(v4_pseudo_header, sizeof(v4_pseudo_header))) - << "ipv4_pseudo_header_checksum incorrect\n"; - - uint8_t v6_header[] = { IPV6_UDP_HEADER }; - uint8_t v6_pseudo_header[] = { IPV6_PSEUDOHEADER(v6_header, IPPROTO_UDP, UDP_LEN) }; - pseudo_checksum = ipv6_pseudo_header_checksum((struct ip6_hdr *)v6_header, UDP_LEN, IPPROTO_UDP); - EXPECT_EQ(ip_checksum_finish(pseudo_checksum), - ip_checksum(v6_pseudo_header, sizeof(v6_pseudo_header))) - << "ipv6_pseudo_header_checksum incorrect\n"; -} - -TEST_F(ClatdTest, TransportChecksum) { - uint8_t udphdr[] = { UDP_HEADER }; - uint8_t payload[] = { PAYLOAD }; - EXPECT_EQ(kUdpPartialChecksum, ip_checksum_add(0, udphdr, sizeof(udphdr))) - << "UDP partial checksum\n"; - EXPECT_EQ(kPayloadPartialChecksum, ip_checksum_add(0, payload, sizeof(payload))) - << "Payload partial checksum\n"; - - uint8_t ip[] = { IPV4_UDP_HEADER }; - uint8_t ip6[] = { IPV6_UDP_HEADER }; - uint32_t ipv4_pseudo_sum = ipv4_pseudo_header_checksum((struct iphdr *)ip, UDP_LEN); - uint32_t ipv6_pseudo_sum = - ipv6_pseudo_header_checksum((struct ip6_hdr *)ip6, UDP_LEN, IPPROTO_UDP); - - EXPECT_NE(0, ipv4_pseudo_sum); - EXPECT_NE(0, ipv6_pseudo_sum); - EXPECT_EQ(0x3ad0U, ipv4_pseudo_sum % 0xFFFF) << "IPv4 pseudo-checksum sanity check\n"; - EXPECT_EQ(0x644dU, ipv6_pseudo_sum % 0xFFFF) << "IPv6 pseudo-checksum sanity check\n"; - EXPECT_EQ( - kUdpV4Checksum, - ip_checksum_finish(ipv4_pseudo_sum + kUdpPartialChecksum + kPayloadPartialChecksum)) - << "Unexpected UDP/IPv4 checksum\n"; - EXPECT_EQ( - kUdpV6Checksum, - ip_checksum_finish(ipv6_pseudo_sum + kUdpPartialChecksum + kPayloadPartialChecksum)) - << "Unexpected UDP/IPv6 checksum\n"; - - EXPECT_EQ(kUdpV6Checksum, - ip_checksum_adjust(kUdpV4Checksum, ipv4_pseudo_sum, ipv6_pseudo_sum)) - << "Adjust IPv4/UDP checksum to IPv6\n"; - EXPECT_EQ(kUdpV4Checksum, - ip_checksum_adjust(kUdpV6Checksum, ipv6_pseudo_sum, ipv4_pseudo_sum)) - << "Adjust IPv6/UDP checksum to IPv4\n"; -} - -TEST_F(ClatdTest, AdjustChecksum) { - struct checksum_data { - uint16_t checksum; - uint32_t old_hdr_sum; - uint32_t new_hdr_sum; - uint16_t result; - } DATA[] = { - { 0x1423, 0xb8ec, 0x2d757, 0xf5b5 }, - { 0xf5b5, 0x2d757, 0xb8ec, 0x1423 }, - { 0xdd2f, 0x5555, 0x3285, 0x0000 }, - { 0x1215, 0x5560, 0x15560 + 20, 0x1200 }, - { 0xd0c7, 0x3ad0, 0x2644b, 0xa74a }, - }; - unsigned i = 0; - - for (i = 0; i < ARRAYSIZE(DATA); i++) { - struct checksum_data *data = DATA + i; - uint16_t result = ip_checksum_adjust(data->checksum, data->old_hdr_sum, data->new_hdr_sum); - EXPECT_EQ(result, data->result) - << "Incorrect checksum" << std::showbase << std::hex - << "\n Expected: " << data->result - << "\n Actual: " << result - << "\n checksum=" << data->checksum - << " old_sum=" << data->old_hdr_sum << " new_sum=" << data->new_hdr_sum << "\n"; - } -} - -TEST_F(ClatdTest, Translate) { - // This test uses hardcoded packets so the clatd address must be fixed. - inet_pton(AF_INET6, kIPv6LocalAddr, &Global_Clatd_Config.ipv6_local_subnet); - - uint8_t udp_ipv4[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD }; - uint8_t udp_ipv6[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD }; - fix_udp_checksum(udp_ipv4); - fix_udp_checksum(udp_ipv6); - check_translated_packet(udp_ipv4, sizeof(udp_ipv4), udp_ipv6, sizeof(udp_ipv6), - "UDP/IPv4 -> UDP/IPv6 translation"); - check_translated_packet(udp_ipv6, sizeof(udp_ipv6), udp_ipv4, sizeof(udp_ipv4), - "UDP/IPv6 -> UDP/IPv4 translation"); - - uint8_t ipv4_ping[] = { IPV4_ICMP_HEADER IPV4_PING PAYLOAD }; - uint8_t ipv6_ping[] = { IPV6_ICMPV6_HEADER IPV6_PING PAYLOAD }; - check_translated_packet(ipv4_ping, sizeof(ipv4_ping), ipv6_ping, sizeof(ipv6_ping), - "ICMP->ICMPv6 translation"); - check_translated_packet(ipv6_ping, sizeof(ipv6_ping), ipv4_ping, sizeof(ipv4_ping), - "ICMPv6->ICMP translation"); -} - -TEST_F(ClatdTest, Fragmentation) { - // This test uses hardcoded packets so the clatd address must be fixed. - inet_pton(AF_INET6, kIPv6LocalAddr, &Global_Clatd_Config.ipv6_local_subnet); - - check_fragment_translation(kIPv4Fragments, kIPv4FragLengths, kIPv6Fragments, kIPv6FragLengths, - ARRAYSIZE(kIPv4Fragments), "IPv4->IPv6 fragment translation"); - - check_fragment_translation(kIPv6Fragments, kIPv6FragLengths, kIPv4Fragments, kIPv4FragLengths, - ARRAYSIZE(kIPv6Fragments), "IPv6->IPv4 fragment translation"); -} - -// picks a random interface ID that is checksum neutral with the IPv4 address and the NAT64 prefix -void gen_random_iid(struct in6_addr *myaddr, struct in_addr *ipv4_local_subnet, - struct in6_addr *plat_subnet) { - // Fill last 8 bytes of IPv6 address with random bits. - arc4random_buf(&myaddr->s6_addr[8], 8); - - // Make the IID checksum-neutral. That is, make it so that: - // checksum(Local IPv4 | Remote IPv4) = checksum(Local IPv6 | Remote IPv6) - // in other words (because remote IPv6 = NAT64 prefix | Remote IPv4): - // checksum(Local IPv4) = checksum(Local IPv6 | NAT64 prefix) - // Do this by adjusting the two bytes in the middle of the IID. - - uint16_t middlebytes = (myaddr->s6_addr[11] << 8) + myaddr->s6_addr[12]; - - uint32_t c1 = ip_checksum_add(0, ipv4_local_subnet, sizeof(*ipv4_local_subnet)); - uint32_t c2 = ip_checksum_add(0, plat_subnet, sizeof(*plat_subnet)) + - ip_checksum_add(0, myaddr, sizeof(*myaddr)); - - uint16_t delta = ip_checksum_adjust(middlebytes, c1, c2); - myaddr->s6_addr[11] = delta >> 8; - myaddr->s6_addr[12] = delta & 0xff; -} - -void check_translate_checksum_neutral(const uint8_t *original, size_t original_len, - size_t expected_len, const char *msg) { - uint8_t translated[MAXMTU]; - size_t translated_len = sizeof(translated); - do_translate_packet(original, original_len, translated, &translated_len, msg); - EXPECT_EQ(expected_len, translated_len) << msg << ": Translated packet length incorrect\n"; - // do_translate_packet already checks packets for validity and verifies the checksum. - int original_check = get_transport_checksum(original); - int translated_check = get_transport_checksum(translated); - ASSERT_NE(-1, original_check); - ASSERT_NE(-1, translated_check); - ASSERT_EQ(original_check, translated_check) - << "Not checksum neutral: original and translated checksums differ\n"; -} - -TEST_F(ClatdTest, TranslateChecksumNeutral) { - // Generate a random clat IPv6 address and check that translation is checksum-neutral. - ASSERT_TRUE(inet_pton(AF_INET6, "2001:db8:1:2:f076:ae99:124e:aa54", - &Global_Clatd_Config.ipv6_local_subnet)); - - gen_random_iid(&Global_Clatd_Config.ipv6_local_subnet, &Global_Clatd_Config.ipv4_local_subnet, - &Global_Clatd_Config.plat_subnet); - - ASSERT_NE(htonl((uint32_t)0x00000464), Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]); - ASSERT_NE((uint32_t)0, Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]); - - // Check that translating UDP packets is checksum-neutral. First, IPv4. - uint8_t udp_ipv4[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD }; - fix_udp_checksum(udp_ipv4); - check_translate_checksum_neutral(udp_ipv4, sizeof(udp_ipv4), sizeof(udp_ipv4) + 20, - "UDP/IPv4 -> UDP/IPv6 checksum neutral"); - - // Now try IPv6. - uint8_t udp_ipv6[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD }; - // The test packet uses the static IID, not the random IID. Fix up the source address. - struct ip6_hdr *ip6 = (struct ip6_hdr *)udp_ipv6; - memcpy(&ip6->ip6_src, &Global_Clatd_Config.ipv6_local_subnet, sizeof(ip6->ip6_src)); - fix_udp_checksum(udp_ipv6); - check_translate_checksum_neutral(udp_ipv4, sizeof(udp_ipv4), sizeof(udp_ipv4) + 20, - "UDP/IPv4 -> UDP/IPv6 checksum neutral"); -} diff --git a/common.h b/common.h deleted file mode 100644 index e9551ee..0000000 --- a/common.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * common.h - common definitions - */ -#ifndef __CLATD_COMMON_H__ -#define __CLATD_COMMON_H__ - -#include <sys/uio.h> - -// A clat_packet is an array of iovec structures representing a packet that we are translating. -// The CLAT_POS_XXX constants represent the array indices within the clat_packet that contain -// specific parts of the packet. The packet_* functions operate on all the packet segments past a -// given position. -typedef enum { - CLAT_POS_TUNHDR, - CLAT_POS_IPHDR, - CLAT_POS_FRAGHDR, - CLAT_POS_TRANSPORTHDR, - CLAT_POS_ICMPERR_IPHDR, - CLAT_POS_ICMPERR_FRAGHDR, - CLAT_POS_ICMPERR_TRANSPORTHDR, - CLAT_POS_PAYLOAD, - CLAT_POS_MAX -} clat_packet_index; -typedef struct iovec clat_packet[CLAT_POS_MAX]; - -#endif /* __CLATD_COMMON_H__ */ diff --git a/config.h b/config.h deleted file mode 100644 index 9612192..0000000 --- a/config.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2011 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * config.h - configuration settings - */ -#ifndef __CONFIG_H__ -#define __CONFIG_H__ - -#include <linux/if.h> -#include <netinet/in.h> - -struct tun_data { - char device4[IFNAMSIZ]; - int read_fd6, write_fd6, fd4; -}; - -struct clat_config { - struct in6_addr ipv6_local_subnet; - struct in_addr ipv4_local_subnet; - struct in6_addr plat_subnet; - const char *native_ipv6_interface; -}; - -extern struct clat_config Global_Clatd_Config; - -/* function: ipv6_prefix_equal - * compares the /64 prefixes of two ipv6 addresses. - * a1 - first address - * a2 - second address - * returns: 0 if the subnets are different, 1 if they are the same. - */ -static inline int ipv6_prefix_equal(struct in6_addr *a1, struct in6_addr *a2) { - return !memcmp(a1, a2, 8); -} - -#endif /* __CONFIG_H__ */ diff --git a/debug.h b/debug.h deleted file mode 100644 index 8e09672..0000000 --- a/debug.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2011 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * debug.h - debug settings - */ -#ifndef __DEBUG_H__ -#define __DEBUG_H__ - -// set to 1 to enable debug logging and packet dumping. -#define CLAT_DEBUG 0 - -#endif /* __DEBUG_H__ */ @@ -1,250 +0,0 @@ -/* - * Copyright 2011 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * dump.c - print various headers for debugging - */ -#include "dump.h" - -#include <arpa/inet.h> -#include <linux/icmp.h> -#include <linux/if_tun.h> -#include <netinet/icmp6.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/ip6.h> -#include <netinet/ip_icmp.h> -#include <netinet/tcp.h> -#include <netinet/udp.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include "checksum.h" -#include "clatd.h" -#include "debug.h" -#include "logging.h" - -#if CLAT_DEBUG - -/* print ip header */ -void dump_ip(struct iphdr *header) { - u_int16_t frag_flags; - char addrstr[INET6_ADDRSTRLEN]; - - frag_flags = ntohs(header->frag_off); - - printf("IP packet\n"); - printf("header_len = %x\n", header->ihl); - printf("version = %x\n", header->version); - printf("tos = %x\n", header->tos); - printf("tot_len = %x\n", ntohs(header->tot_len)); - printf("id = %x\n", ntohs(header->id)); - printf("frag: "); - if (frag_flags & IP_RF) { - printf("(RF) "); - } - if (frag_flags & IP_DF) { - printf("DF "); - } - if (frag_flags & IP_MF) { - printf("MF "); - } - printf("offset = %x\n", frag_flags & IP_OFFMASK); - printf("ttl = %x\n", header->ttl); - printf("protocol = %x\n", header->protocol); - printf("checksum = %x\n", ntohs(header->check)); - inet_ntop(AF_INET, &header->saddr, addrstr, sizeof(addrstr)); - printf("saddr = %s\n", addrstr); - inet_ntop(AF_INET, &header->daddr, addrstr, sizeof(addrstr)); - printf("daddr = %s\n", addrstr); -} - -/* print ip6 header */ -void dump_ip6(struct ip6_hdr *header) { - char addrstr[INET6_ADDRSTRLEN]; - - printf("ipv6\n"); - printf("version = %x\n", header->ip6_vfc >> 4); - printf("traffic class = %x\n", header->ip6_flow >> 20); - printf("flow label = %x\n", ntohl(header->ip6_flow & 0x000fffff)); - printf("payload len = %x\n", ntohs(header->ip6_plen)); - printf("next header = %x\n", header->ip6_nxt); - printf("hop limit = %x\n", header->ip6_hlim); - - inet_ntop(AF_INET6, &header->ip6_src, addrstr, sizeof(addrstr)); - printf("source = %s\n", addrstr); - - inet_ntop(AF_INET6, &header->ip6_dst, addrstr, sizeof(addrstr)); - printf("dest = %s\n", addrstr); -} - -/* print icmp header */ -void dump_icmp(struct icmphdr *icmp) { - printf("ICMP\n"); - - printf("icmp.type = %x ", icmp->type); - if (icmp->type == ICMP_ECHOREPLY) { - printf("echo reply"); - } else if (icmp->type == ICMP_ECHO) { - printf("echo request"); - } else { - printf("other"); - } - printf("\n"); - printf("icmp.code = %x\n", icmp->code); - printf("icmp.checksum = %x\n", ntohs(icmp->checksum)); - if (icmp->type == ICMP_ECHOREPLY || icmp->type == ICMP_ECHO) { - printf("icmp.un.echo.id = %x\n", ntohs(icmp->un.echo.id)); - printf("icmp.un.echo.sequence = %x\n", ntohs(icmp->un.echo.sequence)); - } -} - -/* print icmp6 header */ -void dump_icmp6(struct icmp6_hdr *icmp6) { - printf("ICMP6\n"); - printf("type = %x", icmp6->icmp6_type); - if (icmp6->icmp6_type == ICMP6_ECHO_REQUEST) { - printf("(echo request)"); - } else if (icmp6->icmp6_type == ICMP6_ECHO_REPLY) { - printf("(echo reply)"); - } - printf("\n"); - printf("code = %x\n", icmp6->icmp6_code); - - printf("checksum = %x\n", icmp6->icmp6_cksum); - - if ((icmp6->icmp6_type == ICMP6_ECHO_REQUEST) || (icmp6->icmp6_type == ICMP6_ECHO_REPLY)) { - printf("icmp6_id = %x\n", icmp6->icmp6_id); - printf("icmp6_seq = %x\n", icmp6->icmp6_seq); - } -} - -/* print udp header */ -void dump_udp_generic(const struct udphdr *udp, uint32_t temp_checksum, const uint8_t *payload, - size_t payload_size) { - uint16_t my_checksum; - - temp_checksum = ip_checksum_add(temp_checksum, udp, sizeof(struct udphdr)); - temp_checksum = ip_checksum_add(temp_checksum, payload, payload_size); - my_checksum = ip_checksum_finish(temp_checksum); - - printf("UDP\n"); - printf("source = %x\n", ntohs(udp->source)); - printf("dest = %x\n", ntohs(udp->dest)); - printf("len = %x\n", ntohs(udp->len)); - printf("check = %x (mine %x)\n", udp->check, my_checksum); -} - -/* print ipv4/udp header */ -void dump_udp(const struct udphdr *udp, const struct iphdr *ip, const uint8_t *payload, - size_t payload_size) { - uint32_t temp_checksum; - temp_checksum = ipv4_pseudo_header_checksum(ip, sizeof(*udp) + payload_size); - dump_udp_generic(udp, temp_checksum, payload, payload_size); -} - -/* print ipv6/udp header */ -void dump_udp6(const struct udphdr *udp, const struct ip6_hdr *ip6, const uint8_t *payload, - size_t payload_size) { - uint32_t temp_checksum; - temp_checksum = ipv6_pseudo_header_checksum(ip6, sizeof(*udp) + payload_size, IPPROTO_UDP); - dump_udp_generic(udp, temp_checksum, payload, payload_size); -} - -/* print tcp header */ -void dump_tcp_generic(const struct tcphdr *tcp, const uint8_t *options, size_t options_size, - uint32_t temp_checksum, const uint8_t *payload, size_t payload_size) { - uint16_t my_checksum; - - temp_checksum = ip_checksum_add(temp_checksum, tcp, sizeof(struct tcphdr)); - if (options) { - temp_checksum = ip_checksum_add(temp_checksum, options, options_size); - } - temp_checksum = ip_checksum_add(temp_checksum, payload, payload_size); - my_checksum = ip_checksum_finish(temp_checksum); - - printf("TCP\n"); - printf("source = %x\n", ntohs(tcp->source)); - printf("dest = %x\n", ntohs(tcp->dest)); - printf("seq = %x\n", ntohl(tcp->seq)); - printf("ack = %x\n", ntohl(tcp->ack_seq)); - printf("d_off = %x\n", tcp->doff); - printf("res1 = %x\n", tcp->res1); -#ifdef __BIONIC__ - printf("CWR = %x\n", tcp->cwr); - printf("ECE = %x\n", tcp->ece); -#else - printf("CWR/ECE = %x\n", tcp->res2); -#endif - printf("urg = %x ack = %x psh = %x rst = %x syn = %x fin = %x\n", tcp->urg, tcp->ack, - tcp->psh, tcp->rst, tcp->syn, tcp->fin); - printf("window = %x\n", ntohs(tcp->window)); - printf("check = %x [mine %x]\n", tcp->check, my_checksum); - printf("urgent = %x\n", tcp->urg_ptr); - - if (options) { - size_t i; - - printf("options: "); - for (i = 0; i < options_size; i++) { - printf("%x ", *(options + i)); - } - printf("\n"); - } -} - -/* print ipv4/tcp header */ -void dump_tcp(const struct tcphdr *tcp, const struct iphdr *ip, const uint8_t *payload, - size_t payload_size, const uint8_t *options, size_t options_size) { - uint32_t temp_checksum; - - temp_checksum = ipv4_pseudo_header_checksum(ip, sizeof(*tcp) + options_size + payload_size); - dump_tcp_generic(tcp, options, options_size, temp_checksum, payload, payload_size); -} - -/* print ipv6/tcp header */ -void dump_tcp6(const struct tcphdr *tcp, const struct ip6_hdr *ip6, const uint8_t *payload, - size_t payload_size, const uint8_t *options, size_t options_size) { - uint32_t temp_checksum; - - temp_checksum = - ipv6_pseudo_header_checksum(ip6, sizeof(*tcp) + options_size + payload_size, IPPROTO_TCP); - dump_tcp_generic(tcp, options, options_size, temp_checksum, payload, payload_size); -} - -/* generic hex dump */ -void logcat_hexdump(const char *info, const uint8_t *data, size_t len) { - char output[MAXDUMPLEN * 3 + 2]; - size_t i; - - output[0] = '\0'; - for (i = 0; i < len && i < MAXDUMPLEN; i++) { - snprintf(output + i * 3, 4, " %02x", data[i]); - } - output[len * 3 + 3] = '\0'; - - logmsg(ANDROID_LOG_WARN, "info %s len %d data%s", info, len, output); -} - -void dump_iovec(const struct iovec *iov, int iov_len) { - int i; - char *str; - for (i = 0; i < iov_len; i++) { - asprintf(&str, "iov[%d]: ", i); - logcat_hexdump(str, iov[i].iov_base, iov[i].iov_len); - free(str); - } -} -#endif // CLAT_DEBUG @@ -1,46 +0,0 @@ -/* - * Copyright 2011 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * dump.h - debug functions - */ -#ifndef __DUMP_H__ -#define __DUMP_H__ - -#include <netinet/icmp6.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/ip6.h> -#include <netinet/ip_icmp.h> -#include <netinet/tcp.h> -#include <netinet/udp.h> - -void dump_ip(struct iphdr *header); -void dump_icmp(struct icmphdr *icmp); -void dump_udp(const struct udphdr *udp, const struct iphdr *ip, const uint8_t *payload, - size_t payload_size); -void dump_tcp(const struct tcphdr *tcp, const struct iphdr *ip, const uint8_t *payload, - size_t payload_size, const uint8_t *options, size_t options_size); - -void dump_ip6(struct ip6_hdr *header); -void dump_icmp6(struct icmp6_hdr *icmp6); -void dump_udp6(const struct udphdr *udp, const struct ip6_hdr *ip6, const uint8_t *payload, - size_t payload_size); -void dump_tcp6(const struct tcphdr *tcp, const struct ip6_hdr *ip6, const uint8_t *payload, - size_t payload_size, const uint8_t *options, size_t options_size); - -void logcat_hexdump(const char *info, const uint8_t *data, size_t len); -void dump_iovec(const struct iovec *iov, int iov_len); - -#endif /* __DUMP_H__ */ @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * icmp.c - convenience functions for translating ICMP and ICMPv6 packets. - */ - -#include <linux/icmp.h> -#include <netinet/icmp6.h> -#include <netinet/in.h> -#include <netinet/ip_icmp.h> - -#include "icmp.h" -#include "logging.h" - -/* function: icmp_guess_ttl - * Guesses the number of hops a received packet has traversed based on its TTL. - * ttl - the ttl of the received packet. - */ -uint8_t icmp_guess_ttl(uint8_t ttl) { - if (ttl > 128) { - return 255 - ttl; - } else if (ttl > 64) { - return 128 - ttl; - } else if (ttl > 32) { - return 64 - ttl; - } else { - return 32 - ttl; - } -} - -/* function: is_icmp_error - * Determines whether an ICMP type is an error message. - * type: the ICMP type - */ -int is_icmp_error(uint8_t type) { return type == 3 || type == 11 || type == 12; } - -/* function: is_icmp6_error - * Determines whether an ICMPv6 type is an error message. - * type: the ICMPv6 type - */ -int is_icmp6_error(uint8_t type) { return type < 128; } - -/* function: icmp_to_icmp6_type - * Maps ICMP types to ICMPv6 types. Partial implementation of RFC 6145, section 4.2. - * type - the ICMPv6 type - */ -uint8_t icmp_to_icmp6_type(uint8_t type, uint8_t code) { - switch (type) { - case ICMP_ECHO: - return ICMP6_ECHO_REQUEST; - - case ICMP_ECHOREPLY: - return ICMP6_ECHO_REPLY; - - case ICMP_TIME_EXCEEDED: - return ICMP6_TIME_EXCEEDED; - - case ICMP_DEST_UNREACH: - // These two types need special translation which we don't support yet. - if (code != ICMP_UNREACH_PROTOCOL && code != ICMP_UNREACH_NEEDFRAG) { - return ICMP6_DST_UNREACH; - } - } - - // We don't understand this ICMP type. Return parameter problem so the caller will bail out. - logmsg_dbg(ANDROID_LOG_DEBUG, "icmp_to_icmp6_type: unhandled ICMP type %d", type); - return ICMP6_PARAM_PROB; -} - -/* function: icmp_to_icmp6_code - * Maps ICMP codes to ICMPv6 codes. Partial implementation of RFC 6145, section 4.2. - * type - the ICMP type - * code - the ICMP code - */ -uint8_t icmp_to_icmp6_code(uint8_t type, uint8_t code) { - switch (type) { - case ICMP_ECHO: - case ICMP_ECHOREPLY: - return 0; - - case ICMP_TIME_EXCEEDED: - return code; - - case ICMP_DEST_UNREACH: - switch (code) { - case ICMP_UNREACH_NET: - case ICMP_UNREACH_HOST: - return ICMP6_DST_UNREACH_NOROUTE; - - case ICMP_UNREACH_PORT: - return ICMP6_DST_UNREACH_NOPORT; - - case ICMP_UNREACH_NET_PROHIB: - case ICMP_UNREACH_HOST_PROHIB: - case ICMP_UNREACH_FILTER_PROHIB: - case ICMP_UNREACH_PRECEDENCE_CUTOFF: - return ICMP6_DST_UNREACH_ADMIN; - - // Otherwise, we don't understand this ICMP type/code combination. Fall through. - } - } - logmsg_dbg(ANDROID_LOG_DEBUG, "icmp_to_icmp6_code: unhandled ICMP type/code %d/%d", type, code); - return 0; -} - -/* function: icmp6_to_icmp_type - * Maps ICMPv6 types to ICMP types. Partial implementation of RFC 6145, section 5.2. - * type - the ICMP type - */ -uint8_t icmp6_to_icmp_type(uint8_t type, uint8_t code) { - switch (type) { - case ICMP6_ECHO_REQUEST: - return ICMP_ECHO; - - case ICMP6_ECHO_REPLY: - return ICMP_ECHOREPLY; - - case ICMP6_DST_UNREACH: - return ICMP_DEST_UNREACH; - - case ICMP6_TIME_EXCEEDED: - return ICMP_TIME_EXCEEDED; - } - - // We don't understand this ICMP type. Return parameter problem so the caller will bail out. - logmsg_dbg(ANDROID_LOG_DEBUG, "icmp6_to_icmp_type: unhandled ICMP type/code %d/%d", type, code); - return ICMP_PARAMETERPROB; -} - -/* function: icmp6_to_icmp_code - * Maps ICMPv6 codes to ICMP codes. Partial implementation of RFC 6145, section 5.2. - * type - the ICMPv6 type - * code - the ICMPv6 code - */ -uint8_t icmp6_to_icmp_code(uint8_t type, uint8_t code) { - switch (type) { - case ICMP6_ECHO_REQUEST: - case ICMP6_ECHO_REPLY: - case ICMP6_TIME_EXCEEDED: - return code; - - case ICMP6_DST_UNREACH: - switch (code) { - case ICMP6_DST_UNREACH_NOROUTE: - return ICMP_UNREACH_HOST; - - case ICMP6_DST_UNREACH_ADMIN: - return ICMP_UNREACH_HOST_PROHIB; - - case ICMP6_DST_UNREACH_BEYONDSCOPE: - return ICMP_UNREACH_HOST; - - case ICMP6_DST_UNREACH_ADDR: - return ICMP_HOST_UNREACH; - - case ICMP6_DST_UNREACH_NOPORT: - return ICMP_UNREACH_PORT; - - // Otherwise, we don't understand this ICMPv6 type/code combination. Fall through. - } - } - - logmsg_dbg(ANDROID_LOG_DEBUG, "icmp6_to_icmp_code: unhandled ICMP type/code %d/%d", type, code); - return 0; -} @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * icmp.c - convenience functions for translating ICMP and ICMPv6 packets. - */ - -#ifndef __ICMP_H__ -#define __ICMP_H__ - -#include <stdint.h> - -// Guesses the number of hops a received packet has traversed based on its TTL. -uint8_t icmp_guess_ttl(uint8_t ttl); - -// Determines whether an ICMP type is an error message. -int is_icmp_error(uint8_t type); - -// Determines whether an ICMPv6 type is an error message. -int is_icmp6_error(uint8_t type); - -// Maps ICMP types to ICMPv6 types. Partial implementation of RFC 6145, section 4.2. -uint8_t icmp_to_icmp6_type(uint8_t type, uint8_t code); - -// Maps ICMP codes to ICMPv6 codes. Partial implementation of RFC 6145, section 4.2. -uint8_t icmp_to_icmp6_code(uint8_t type, uint8_t code); - -// Maps ICMPv6 types to ICMP types. Partial implementation of RFC 6145, section 5.2. -uint8_t icmp6_to_icmp_type(uint8_t type, uint8_t code); - -// Maps ICMPv6 codes to ICMP codes. Partial implementation of RFC 6145, section 5.2. -uint8_t icmp6_to_icmp_code(uint8_t type, uint8_t code); - -#endif /* __ICMP_H__ */ @@ -1,146 +0,0 @@ -/* - * Copyright 2011 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ipv4.c - takes ipv4 packets, finds their headers, and then calls translation functions on them - */ -#include <string.h> - -#include "checksum.h" -#include "debug.h" -#include "dump.h" -#include "logging.h" -#include "translate.h" - -/* function: icmp_packet - * translates an icmp packet - * out - output packet - * icmp - pointer to icmp header in packet - * checksum - pseudo-header checksum - * len - size of ip payload - * returns: the highest position in the output clat_packet that's filled in - */ -int icmp_packet(clat_packet out, clat_packet_index pos, const struct icmphdr *icmp, - uint32_t checksum, size_t len) { - const uint8_t *payload; - size_t payload_size; - - if (len < sizeof(struct icmphdr)) { - logmsg_dbg(ANDROID_LOG_ERROR, "icmp_packet/(too small)"); - return 0; - } - - payload = (const uint8_t *)(icmp + 1); - payload_size = len - sizeof(struct icmphdr); - - return icmp_to_icmp6(out, pos, icmp, checksum, payload, payload_size); -} - -/* function: ipv4_packet - * translates an ipv4 packet - * out - output packet - * packet - packet data - * len - size of packet - * returns: the highest position in the output clat_packet that's filled in - */ -int ipv4_packet(clat_packet out, clat_packet_index pos, const uint8_t *packet, size_t len) { - const struct iphdr *header = (struct iphdr *)packet; - struct ip6_hdr *ip6_targ = (struct ip6_hdr *)out[pos].iov_base; - struct ip6_frag *frag_hdr; - size_t frag_hdr_len; - uint8_t nxthdr; - const uint8_t *next_header; - size_t len_left; - uint32_t old_sum, new_sum; - int iov_len; - - if (len < sizeof(struct iphdr)) { - logmsg_dbg(ANDROID_LOG_ERROR, "ip_packet/too short for an ip header"); - return 0; - } - - if (header->ihl < 5) { - logmsg_dbg(ANDROID_LOG_ERROR, "ip_packet/ip header length set to less than 5: %x", header->ihl); - return 0; - } - - if ((size_t)header->ihl * 4 > len) { // ip header length larger than entire packet - logmsg_dbg(ANDROID_LOG_ERROR, "ip_packet/ip header length set too large: %x", header->ihl); - return 0; - } - - if (header->version != 4) { - logmsg_dbg(ANDROID_LOG_ERROR, "ip_packet/ip header version not 4: %x", header->version); - return 0; - } - - /* rfc6145 - If any IPv4 options are present in the IPv4 packet, they MUST be - * ignored and the packet translated normally; there is no attempt to - * translate the options. - */ - - next_header = packet + header->ihl * 4; - len_left = len - header->ihl * 4; - - nxthdr = header->protocol; - if (nxthdr == IPPROTO_ICMP) { - // ICMP and ICMPv6 have different protocol numbers. - nxthdr = IPPROTO_ICMPV6; - } - - /* Fill in the IPv6 header. We need to do this before we translate the packet because TCP and - * UDP include parts of the IP header in the checksum. Set the length to zero because we don't - * know it yet. - */ - fill_ip6_header(ip6_targ, 0, nxthdr, header); - out[pos].iov_len = sizeof(struct ip6_hdr); - - /* Calculate the pseudo-header checksum. - * Technically, the length that is used in the pseudo-header checksum is the transport layer - * length, which is not the same as len_left in the case of fragmented packets. But since - * translation does not change the transport layer length, the checksum is unaffected. - */ - old_sum = ipv4_pseudo_header_checksum(header, len_left); - new_sum = ipv6_pseudo_header_checksum(ip6_targ, len_left, nxthdr); - - // If the IPv4 packet is fragmented, add a Fragment header. - frag_hdr = (struct ip6_frag *)out[pos + 1].iov_base; - frag_hdr_len = maybe_fill_frag_header(frag_hdr, ip6_targ, header); - out[pos + 1].iov_len = frag_hdr_len; - - if (frag_hdr_len && frag_hdr->ip6f_offlg & IP6F_OFF_MASK) { - // Non-first fragment. Copy the rest of the packet as is. - iov_len = generic_packet(out, pos + 2, next_header, len_left); - } else if (nxthdr == IPPROTO_ICMPV6) { - iov_len = icmp_packet(out, pos + 2, (const struct icmphdr *)next_header, new_sum, len_left); - } else if (nxthdr == IPPROTO_TCP) { - iov_len = - tcp_packet(out, pos + 2, (const struct tcphdr *)next_header, old_sum, new_sum, len_left); - } else if (nxthdr == IPPROTO_UDP) { - iov_len = - udp_packet(out, pos + 2, (const struct udphdr *)next_header, old_sum, new_sum, len_left); - } else if (nxthdr == IPPROTO_GRE || nxthdr == IPPROTO_ESP) { - iov_len = generic_packet(out, pos + 2, next_header, len_left); - } else { -#if CLAT_DEBUG - logmsg_dbg(ANDROID_LOG_ERROR, "ip_packet/unknown protocol: %x", header->protocol); - logcat_hexdump("ipv4/protocol", packet, len); -#endif - return 0; - } - - // Set the length. - ip6_targ->ip6_plen = htons(packet_length(out, pos)); - return iov_len; -} @@ -1,178 +0,0 @@ -/* - * Copyright 2011 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ipv6.c - takes ipv6 packets, finds their headers, and then calls translation functions on them - */ -#include <arpa/inet.h> -#include <string.h> - -#include "checksum.h" -#include "config.h" -#include "debug.h" -#include "dump.h" -#include "logging.h" -#include "translate.h" - -/* function: icmp6_packet - * takes an icmp6 packet and sets it up for translation - * out - output packet - * icmp6 - pointer to icmp6 header in packet - * checksum - pseudo-header checksum (unused) - * len - size of ip payload - * returns: the highest position in the output clat_packet that's filled in - */ -int icmp6_packet(clat_packet out, clat_packet_index pos, const struct icmp6_hdr *icmp6, - size_t len) { - const uint8_t *payload; - size_t payload_size; - - if (len < sizeof(struct icmp6_hdr)) { - logmsg_dbg(ANDROID_LOG_ERROR, "icmp6_packet/(too small)"); - return 0; - } - - payload = (const uint8_t *)(icmp6 + 1); - payload_size = len - sizeof(struct icmp6_hdr); - - return icmp6_to_icmp(out, pos, icmp6, payload, payload_size); -} - -/* function: log_bad_address - * logs a bad address to android's log buffer if debugging is turned on - * fmt - printf-style format, use %s to place the address - * badaddr - the bad address in question - */ -#if CLAT_DEBUG -void log_bad_address(const char *fmt, const struct in6_addr *src, const struct in6_addr *dst) { - char srcstr[INET6_ADDRSTRLEN]; - char dststr[INET6_ADDRSTRLEN]; - - inet_ntop(AF_INET6, src, srcstr, sizeof(srcstr)); - inet_ntop(AF_INET6, dst, dststr, sizeof(dststr)); - logmsg_dbg(ANDROID_LOG_ERROR, fmt, srcstr, dststr); -} -#else -#define log_bad_address(fmt, src, dst) -#endif - -/* function: ipv6_packet - * takes an ipv6 packet and hands it off to the layer 4 protocol function - * out - output packet - * packet - packet data - * len - size of packet - * returns: the highest position in the output clat_packet that's filled in - */ -int ipv6_packet(clat_packet out, clat_packet_index pos, const uint8_t *packet, size_t len) { - const struct ip6_hdr *ip6 = (struct ip6_hdr *)packet; - struct iphdr *ip_targ = (struct iphdr *)out[pos].iov_base; - struct ip6_frag *frag_hdr = NULL; - uint8_t protocol; - const uint8_t *next_header; - size_t len_left; - uint32_t old_sum, new_sum; - int iov_len; - - if (len < sizeof(struct ip6_hdr)) { - logmsg_dbg(ANDROID_LOG_ERROR, "ipv6_packet/too short for an ip6 header: %d", len); - return 0; - } - - if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { - log_bad_address("ipv6_packet/multicast %s->%s", &ip6->ip6_src, &ip6->ip6_dst); - return 0; // silently ignore - } - - // If the packet is not from the plat subnet to the local subnet, or vice versa, drop it, unless - // it's an ICMP packet (which can come from anywhere). We do not send IPv6 packets from the plat - // subnet to the local subnet, but these can appear as inner packets in ICMP errors, so we need - // to translate them. We accept third-party ICMPv6 errors, even though their source addresses - // cannot be translated, so that things like unreachables and traceroute will work. fill_ip_header - // takes care of faking a source address for them. - if (!(is_in_plat_subnet(&ip6->ip6_src) && - IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &Global_Clatd_Config.ipv6_local_subnet)) && - !(is_in_plat_subnet(&ip6->ip6_dst) && - IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &Global_Clatd_Config.ipv6_local_subnet)) && - ip6->ip6_nxt != IPPROTO_ICMPV6) { - log_bad_address("ipv6_packet/wrong source address: %s->%s", &ip6->ip6_src, &ip6->ip6_dst); - return 0; - } - - next_header = packet + sizeof(struct ip6_hdr); - len_left = len - sizeof(struct ip6_hdr); - - protocol = ip6->ip6_nxt; - - /* Fill in the IPv4 header. We need to do this before we translate the packet because TCP and - * UDP include parts of the IP header in the checksum. Set the length to zero because we don't - * know it yet. - */ - fill_ip_header(ip_targ, 0, protocol, ip6); - out[pos].iov_len = sizeof(struct iphdr); - - // If there's a Fragment header, parse it and decide what the next header is. - // Do this before calculating the pseudo-header checksum because it updates the next header value. - if (protocol == IPPROTO_FRAGMENT) { - frag_hdr = (struct ip6_frag *)next_header; - if (len_left < sizeof(*frag_hdr)) { - logmsg_dbg(ANDROID_LOG_ERROR, "ipv6_packet/too short for fragment header: %d", len); - return 0; - } - - next_header += sizeof(*frag_hdr); - len_left -= sizeof(*frag_hdr); - - protocol = parse_frag_header(frag_hdr, ip_targ); - } - - // ICMP and ICMPv6 have different protocol numbers. - if (protocol == IPPROTO_ICMPV6) { - protocol = IPPROTO_ICMP; - ip_targ->protocol = IPPROTO_ICMP; - } - - /* Calculate the pseudo-header checksum. - * Technically, the length that is used in the pseudo-header checksum is the transport layer - * length, which is not the same as len_left in the case of fragmented packets. But since - * translation does not change the transport layer length, the checksum is unaffected. - */ - old_sum = ipv6_pseudo_header_checksum(ip6, len_left, protocol); - new_sum = ipv4_pseudo_header_checksum(ip_targ, len_left); - - // Does not support IPv6 extension headers except Fragment. - if (frag_hdr && (frag_hdr->ip6f_offlg & IP6F_OFF_MASK)) { - iov_len = generic_packet(out, pos + 2, next_header, len_left); - } else if (protocol == IPPROTO_ICMP) { - iov_len = icmp6_packet(out, pos + 2, (const struct icmp6_hdr *)next_header, len_left); - } else if (protocol == IPPROTO_TCP) { - iov_len = - tcp_packet(out, pos + 2, (const struct tcphdr *)next_header, old_sum, new_sum, len_left); - } else if (protocol == IPPROTO_UDP) { - iov_len = - udp_packet(out, pos + 2, (const struct udphdr *)next_header, old_sum, new_sum, len_left); - } else if (protocol == IPPROTO_GRE || protocol == IPPROTO_ESP) { - iov_len = generic_packet(out, pos + 2, next_header, len_left); - } else { -#if CLAT_DEBUG - logmsg(ANDROID_LOG_ERROR, "ipv6_packet/unknown next header type: %x", ip6->ip6_nxt); - logcat_hexdump("ipv6/nxthdr", packet, len); -#endif - return 0; - } - - // Set the length and calculate the checksum. - ip_targ->tot_len = htons(ntohs(ip_targ->tot_len) + packet_length(out, pos)); - ip_targ->check = ip_checksum(ip_targ, sizeof(struct iphdr)); - return iov_len; -} diff --git a/logging.c b/logging.c deleted file mode 100644 index 79d98e1..0000000 --- a/logging.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2011 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * logging.c - print a log message - */ - -#include <android/log.h> -#include <stdarg.h> - -#include "debug.h" -#include "logging.h" - -/* function: logmsg - * prints a log message to android's log buffer - * prio - the log message priority - * fmt - printf format specifier - * ... - printf format arguments - */ -void logmsg(int prio, const char *fmt, ...) { - va_list ap; - - va_start(ap, fmt); - __android_log_vprint(prio, "clatd", fmt, ap); - va_end(ap); -} - -/* function: logmsg_dbg - * prints a log message to android's log buffer if CLAT_DEBUG is set - * prio - the log message priority - * fmt - printf format specifier - * ... - printf format arguments - */ -#if CLAT_DEBUG -void logmsg_dbg(int prio, const char *fmt, ...) { - va_list ap; - - va_start(ap, fmt); - __android_log_vprint(prio, "clatd", fmt, ap); - va_end(ap); -} -#else -void logmsg_dbg(__attribute__((unused)) int prio, __attribute__((unused)) const char *fmt, ...) {} -#endif diff --git a/logging.h b/logging.h deleted file mode 100644 index 1f4b6b6..0000000 --- a/logging.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2011 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * logging.h - print a log message - */ - -#ifndef __LOGGING_H__ -#define __LOGGING_H__ -// for the priorities -#include <android/log.h> - -void logmsg(int prio, const char *fmt, ...); -void logmsg_dbg(int prio, const char *fmt, ...); - -#endif @@ -1,207 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * main.c - main function - */ - -#include <arpa/inet.h> -#include <errno.h> -#include <netinet/in.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <sys/personality.h> -#include <sys/utsname.h> -#include <unistd.h> - -#include "clatd.h" -#include "common.h" -#include "config.h" -#include "logging.h" - -#define DEVICEPREFIX "v4-" - -/* function: stop_loop - * signal handler: stop the event loop - */ -static void stop_loop() { running = 0; }; - -/* function: print_help - * in case the user is running this on the command line - */ -void print_help() { - printf("android-clat arguments:\n"); - printf("-i [uplink interface]\n"); - printf("-p [plat prefix]\n"); - printf("-4 [IPv4 address]\n"); - printf("-6 [IPv6 address]\n"); - printf("-t [tun file descriptor number]\n"); - printf("-r [read socket descriptor number]\n"); - printf("-w [write socket descriptor number]\n"); -} - -/* function: main - * allocate and setup the tun device, then run the event loop - */ -int main(int argc, char **argv) { - struct tun_data tunnel; - int opt; - char *uplink_interface = NULL, *plat_prefix = NULL; - char *v4_addr = NULL, *v6_addr = NULL, *tunfd_str = NULL, *read_sock_str = NULL, - *write_sock_str = NULL; - unsigned len; - - while ((opt = getopt(argc, argv, "i:p:4:6:t:r:w:h")) != -1) { - switch (opt) { - case 'i': - uplink_interface = optarg; - break; - case 'p': - plat_prefix = optarg; - break; - case '4': - v4_addr = optarg; - break; - case '6': - v6_addr = optarg; - break; - case 't': - tunfd_str = optarg; - break; - case 'r': - read_sock_str = optarg; - break; - case 'w': - write_sock_str = optarg; - break; - case 'h': - print_help(); - exit(0); - default: - logmsg(ANDROID_LOG_FATAL, "Unknown option -%c. Exiting.", (char)optopt); - exit(1); - } - } - - if (uplink_interface == NULL) { - logmsg(ANDROID_LOG_FATAL, "clatd called without an interface"); - exit(1); - } - - if (tunfd_str != NULL && !parse_int(tunfd_str, &tunnel.fd4)) { - logmsg(ANDROID_LOG_FATAL, "invalid tunfd %s", tunfd_str); - exit(1); - } - if (!tunnel.fd4) { - logmsg(ANDROID_LOG_FATAL, "no tunfd specified on commandline."); - exit(1); - } - - if (read_sock_str != NULL && !parse_int(read_sock_str, &tunnel.read_fd6)) { - logmsg(ANDROID_LOG_FATAL, "invalid read socket %s", read_sock_str); - exit(1); - } - if (!tunnel.read_fd6) { - logmsg(ANDROID_LOG_FATAL, "no read_fd6 specified on commandline."); - exit(1); - } - - if (write_sock_str != NULL && !parse_int(write_sock_str, &tunnel.write_fd6)) { - logmsg(ANDROID_LOG_FATAL, "invalid write socket %s", write_sock_str); - exit(1); - } - if (!tunnel.write_fd6) { - logmsg(ANDROID_LOG_FATAL, "no write_fd6 specified on commandline."); - exit(1); - } - - len = snprintf(tunnel.device4, sizeof(tunnel.device4), "%s%s", DEVICEPREFIX, uplink_interface); - if (len >= sizeof(tunnel.device4)) { - logmsg(ANDROID_LOG_FATAL, "interface name too long '%s'", tunnel.device4); - exit(1); - } - - Global_Clatd_Config.native_ipv6_interface = uplink_interface; - if (!plat_prefix || inet_pton(AF_INET6, plat_prefix, &Global_Clatd_Config.plat_subnet) <= 0) { - logmsg(ANDROID_LOG_FATAL, "invalid IPv6 address specified for plat prefix: %s", plat_prefix); - exit(1); - } - - if (!v4_addr || !inet_pton(AF_INET, v4_addr, &Global_Clatd_Config.ipv4_local_subnet.s_addr)) { - logmsg(ANDROID_LOG_FATAL, "Invalid IPv4 address %s", v4_addr); - exit(1); - } - - if (!v6_addr || !inet_pton(AF_INET6, v6_addr, &Global_Clatd_Config.ipv6_local_subnet)) { - logmsg(ANDROID_LOG_FATAL, "Invalid source address %s", v6_addr); - exit(1); - } - - logmsg(ANDROID_LOG_INFO, "Starting clat version %s on %s plat=%s v4=%s v6=%s", CLATD_VERSION, - uplink_interface, plat_prefix ? plat_prefix : "(none)", v4_addr ? v4_addr : "(none)", - v6_addr ? v6_addr : "(none)"); - - { - // Compile time detection of 32 vs 64-bit build. (note: C does not have 'constexpr') - // Avoid use of preprocessor macros to get compile time syntax checking even on 64-bit. - const int user_bits = sizeof(void*) * 8; - const bool user32 = (user_bits == 32); - - // Note that on 64-bit all this personality related code simply compile optimizes out. - // 32-bit: fetch current personality (see 'man personality': 0xFFFFFFFF means retrieve only) - // On Linux fetching personality cannot fail. - const int prev_personality = user32 ? personality(0xFFFFFFFFuL) : PER_LINUX; - // 32-bit: attempt to get rid of kernel spoofing of 'uts.machine' architecture, - // In theory this cannot fail, as PER_LINUX should always be supported. - if (user32) (void)personality((prev_personality & ~PER_MASK) | PER_LINUX); - // 64-bit: this will compile time evaluate to false. - const bool was_linux32 = (prev_personality & PER_MASK) == PER_LINUX32; - - struct utsname uts = {}; - if (uname(&uts)) exit(1); // only possible error is EFAULT, but 'uts' is on stack - - // sysname is likely 'Linux', release is 'kver', machine is kernel's *true* architecture - logmsg(ANDROID_LOG_INFO, "%d-bit userspace on %s kernel %s for %s%s.", user_bits, - uts.sysname, uts.release, uts.machine, was_linux32 ? " (was spoofed)" : ""); - - // 32-bit: try to return to the 'default' personality - // In theory this cannot fail, because it was already previously in use. - if (user32) (void)personality(prev_personality); - } - - // Loop until someone sends us a signal or brings down the tun interface. - if (signal(SIGTERM, stop_loop) == SIG_ERR) { - logmsg(ANDROID_LOG_FATAL, "sigterm handler failed: %s", strerror(errno)); - exit(1); - } - - event_loop(&tunnel); - - logmsg(ANDROID_LOG_INFO, "Shutting down clat on %s", uplink_interface); - - if (running) { - logmsg(ANDROID_LOG_INFO, "Clatd on %s waiting for SIGTERM", uplink_interface); - // let's give higher level java code 15 seconds to kill us, - // but eventually terminate anyway, in case system server forgets about us... - // sleep() should be interrupted by SIGTERM, the handler should clear running - sleep(15); - logmsg(ANDROID_LOG_INFO, "Clatd on %s %s SIGTERM", uplink_interface, - running ? "timed out waiting for" : "received"); - } else { - logmsg(ANDROID_LOG_INFO, "Clatd on %s already received SIGTERM", uplink_interface); - } - return 0; -} diff --git a/translate.c b/translate.c deleted file mode 100644 index 22830d8..0000000 --- a/translate.c +++ /dev/null @@ -1,529 +0,0 @@ -/* - * Copyright 2011 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * translate.c - CLAT functions / partial implementation of rfc6145 - */ -#include "translate.h" - -#include <string.h> - -#include "checksum.h" -#include "clatd.h" -#include "common.h" -#include "config.h" -#include "debug.h" -#include "icmp.h" -#include "logging.h" - -/* function: packet_checksum - * calculates the checksum over all the packet components starting from pos - * checksum - checksum of packet components before pos - * packet - packet to calculate the checksum of - * pos - position to start counting from - * returns - the completed 16-bit checksum, ready to write into a checksum header field - */ -uint16_t packet_checksum(uint32_t checksum, clat_packet packet, clat_packet_index pos) { - int i; - for (i = pos; i < CLAT_POS_MAX; i++) { - if (packet[i].iov_len > 0) { - checksum = ip_checksum_add(checksum, packet[i].iov_base, packet[i].iov_len); - } - } - return ip_checksum_finish(checksum); -} - -/* function: packet_length - * returns the total length of all the packet components after pos - * packet - packet to calculate the length of - * pos - position to start counting after - * returns: the total length of the packet components after pos - */ -uint16_t packet_length(clat_packet packet, clat_packet_index pos) { - size_t len = 0; - int i; - for (i = pos + 1; i < CLAT_POS_MAX; i++) { - len += packet[i].iov_len; - } - return len; -} - -/* function: is_in_plat_subnet - * returns true iff the given IPv6 address is in the plat subnet. - * addr - IPv6 address - */ -int is_in_plat_subnet(const struct in6_addr *addr6) { - // Assumes a /96 plat subnet. - return (addr6 != NULL) && (memcmp(addr6, &Global_Clatd_Config.plat_subnet, 12) == 0); -} - -/* function: ipv6_addr_to_ipv4_addr - * return the corresponding ipv4 address for the given ipv6 address - * addr6 - ipv6 address - * returns: the IPv4 address - */ -uint32_t ipv6_addr_to_ipv4_addr(const struct in6_addr *addr6) { - if (is_in_plat_subnet(addr6)) { - // Assumes a /96 plat subnet. - return addr6->s6_addr32[3]; - } else if (IN6_ARE_ADDR_EQUAL(addr6, &Global_Clatd_Config.ipv6_local_subnet)) { - // Special-case our own address. - return Global_Clatd_Config.ipv4_local_subnet.s_addr; - } else { - // Third party packet. Let the caller deal with it. - return INADDR_NONE; - } -} - -/* function: ipv4_addr_to_ipv6_addr - * return the corresponding ipv6 address for the given ipv4 address - * addr4 - ipv4 address - */ -struct in6_addr ipv4_addr_to_ipv6_addr(uint32_t addr4) { - struct in6_addr addr6; - // Both addresses are in network byte order (addr4 comes from a network packet, and the config - // file entry is read using inet_ntop). - if (addr4 == Global_Clatd_Config.ipv4_local_subnet.s_addr) { - return Global_Clatd_Config.ipv6_local_subnet; - } else { - // Assumes a /96 plat subnet. - addr6 = Global_Clatd_Config.plat_subnet; - addr6.s6_addr32[3] = addr4; - return addr6; - } -} - -/* function: fill_tun_header - * fill in the header for the tun fd - * tun_header - tunnel header, already allocated - * proto - ethernet protocol id: ETH_P_IP(ipv4) or ETH_P_IPV6(ipv6) - */ -void fill_tun_header(struct tun_pi *tun_header, uint16_t proto) { - tun_header->flags = 0; - tun_header->proto = htons(proto); -} - -/* function: fill_ip_header - * generate an ipv4 header from an ipv6 header - * ip_targ - (ipv4) target packet header, source: original ipv4 addr, dest: local subnet addr - * payload_len - length of other data inside packet - * protocol - protocol number (tcp, udp, etc) - * old_header - (ipv6) source packet header, source: nat64 prefix, dest: local subnet prefix - */ -void fill_ip_header(struct iphdr *ip, uint16_t payload_len, uint8_t protocol, - const struct ip6_hdr *old_header) { - int ttl_guess; - memset(ip, 0, sizeof(struct iphdr)); - - ip->ihl = 5; - ip->version = 4; - ip->tos = 0; - ip->tot_len = htons(sizeof(struct iphdr) + payload_len); - ip->id = 0; - ip->frag_off = htons(IP_DF); - ip->ttl = old_header->ip6_hlim; - ip->protocol = protocol; - ip->check = 0; - - ip->saddr = ipv6_addr_to_ipv4_addr(&old_header->ip6_src); - ip->daddr = ipv6_addr_to_ipv4_addr(&old_header->ip6_dst); - - // Third-party ICMPv6 message. This may have been originated by an native IPv6 address. - // In that case, the source IPv6 address can't be translated and we need to make up an IPv4 - // source address. For now, use 255.0.0.<ttl>, which at least looks useful in traceroute. - if ((uint32_t)ip->saddr == INADDR_NONE) { - ttl_guess = icmp_guess_ttl(old_header->ip6_hlim); - ip->saddr = htonl((0xff << 24) + ttl_guess); - } -} - -/* function: fill_ip6_header - * generate an ipv6 header from an ipv4 header - * ip6 - (ipv6) target packet header, source: local subnet prefix, dest: nat64 prefix - * payload_len - length of other data inside packet - * protocol - protocol number (tcp, udp, etc) - * old_header - (ipv4) source packet header, source: local subnet addr, dest: internet's ipv4 addr - */ -void fill_ip6_header(struct ip6_hdr *ip6, uint16_t payload_len, uint8_t protocol, - const struct iphdr *old_header) { - memset(ip6, 0, sizeof(struct ip6_hdr)); - - ip6->ip6_vfc = 6 << 4; - ip6->ip6_plen = htons(payload_len); - ip6->ip6_nxt = protocol; - ip6->ip6_hlim = old_header->ttl; - - ip6->ip6_src = ipv4_addr_to_ipv6_addr(old_header->saddr); - ip6->ip6_dst = ipv4_addr_to_ipv6_addr(old_header->daddr); -} - -/* function: maybe_fill_frag_header - * fills a fragmentation header - * generate an ipv6 fragment header from an ipv4 header - * frag_hdr - target (ipv6) fragmentation header - * ip6_targ - target (ipv6) header - * old_header - (ipv4) source packet header - * returns: the length of the fragmentation header if present, or zero if not present - */ -size_t maybe_fill_frag_header(struct ip6_frag *frag_hdr, struct ip6_hdr *ip6_targ, - const struct iphdr *old_header) { - uint16_t frag_flags = ntohs(old_header->frag_off); - uint16_t frag_off = frag_flags & IP_OFFMASK; - if (frag_off == 0 && (frag_flags & IP_MF) == 0) { - // Not a fragment. - return 0; - } - - frag_hdr->ip6f_nxt = ip6_targ->ip6_nxt; - frag_hdr->ip6f_reserved = 0; - // In IPv4, the offset is the bottom 13 bits; in IPv6 it's the top 13 bits. - frag_hdr->ip6f_offlg = htons(frag_off << 3); - if (frag_flags & IP_MF) { - frag_hdr->ip6f_offlg |= IP6F_MORE_FRAG; - } - frag_hdr->ip6f_ident = htonl(ntohs(old_header->id)); - ip6_targ->ip6_nxt = IPPROTO_FRAGMENT; - - return sizeof(*frag_hdr); -} - -/* function: parse_frag_header - * return the length of the fragmentation header if present, or zero if not present - * generate an ipv6 fragment header from an ipv4 header - * frag_hdr - (ipv6) fragmentation header - * ip_targ - target (ipv4) header - * returns: the next header value - */ -uint8_t parse_frag_header(const struct ip6_frag *frag_hdr, struct iphdr *ip_targ) { - uint16_t frag_off = (ntohs(frag_hdr->ip6f_offlg & IP6F_OFF_MASK) >> 3); - if (frag_hdr->ip6f_offlg & IP6F_MORE_FRAG) { - frag_off |= IP_MF; - } - ip_targ->frag_off = htons(frag_off); - ip_targ->id = htons(ntohl(frag_hdr->ip6f_ident) & 0xffff); - ip_targ->protocol = frag_hdr->ip6f_nxt; - return frag_hdr->ip6f_nxt; -} - -/* function: icmp_to_icmp6 - * translate ipv4 icmp to ipv6 icmp - * out - output packet - * icmp - source packet icmp header - * checksum - pseudo-header checksum - * payload - icmp payload - * payload_size - size of payload - * returns: the highest position in the output clat_packet that's filled in - */ -int icmp_to_icmp6(clat_packet out, clat_packet_index pos, const struct icmphdr *icmp, - uint32_t checksum, const uint8_t *payload, size_t payload_size) { - struct icmp6_hdr *icmp6_targ = out[pos].iov_base; - uint8_t icmp6_type; - int clat_packet_len; - - memset(icmp6_targ, 0, sizeof(struct icmp6_hdr)); - - icmp6_type = icmp_to_icmp6_type(icmp->type, icmp->code); - icmp6_targ->icmp6_type = icmp6_type; - icmp6_targ->icmp6_code = icmp_to_icmp6_code(icmp->type, icmp->code); - - out[pos].iov_len = sizeof(struct icmp6_hdr); - - if (pos == CLAT_POS_TRANSPORTHDR && is_icmp_error(icmp->type) && icmp6_type != ICMP6_PARAM_PROB) { - // An ICMP error we understand, one level deep. - // Translate the nested packet (the one that caused the error). - clat_packet_len = ipv4_packet(out, pos + 1, payload, payload_size); - - // The pseudo-header checksum was calculated on the transport length of the original IPv4 - // packet that we were asked to translate. This transport length is 20 bytes smaller than it - // needs to be, because the ICMP error contains an IPv4 header, which we will be translating to - // an IPv6 header, which is 20 bytes longer. Fix it up here. - // We only need to do this for ICMP->ICMPv6, not ICMPv6->ICMP, because ICMP does not use the - // pseudo-header when calculating its checksum (as the IPv4 header has its own checksum). - checksum = checksum + htons(20); - } else if (icmp6_type == ICMP6_ECHO_REQUEST || icmp6_type == ICMP6_ECHO_REPLY) { - // Ping packet. - icmp6_targ->icmp6_id = icmp->un.echo.id; - icmp6_targ->icmp6_seq = icmp->un.echo.sequence; - out[CLAT_POS_PAYLOAD].iov_base = (uint8_t *)payload; - out[CLAT_POS_PAYLOAD].iov_len = payload_size; - clat_packet_len = CLAT_POS_PAYLOAD + 1; - } else { - // Unknown type/code. The type/code conversion functions have already logged an error. - return 0; - } - - icmp6_targ->icmp6_cksum = 0; // Checksum field must be 0 when calculating checksum. - icmp6_targ->icmp6_cksum = packet_checksum(checksum, out, pos); - - return clat_packet_len; -} - -/* function: icmp6_to_icmp - * translate ipv6 icmp to ipv4 icmp - * out - output packet - * icmp6 - source packet icmp6 header - * payload - icmp6 payload - * payload_size - size of payload - * returns: the highest position in the output clat_packet that's filled in - */ -int icmp6_to_icmp(clat_packet out, clat_packet_index pos, const struct icmp6_hdr *icmp6, - const uint8_t *payload, size_t payload_size) { - struct icmphdr *icmp_targ = out[pos].iov_base; - uint8_t icmp_type; - int clat_packet_len; - - memset(icmp_targ, 0, sizeof(struct icmphdr)); - - icmp_type = icmp6_to_icmp_type(icmp6->icmp6_type, icmp6->icmp6_code); - icmp_targ->type = icmp_type; - icmp_targ->code = icmp6_to_icmp_code(icmp6->icmp6_type, icmp6->icmp6_code); - - out[pos].iov_len = sizeof(struct icmphdr); - - if (pos == CLAT_POS_TRANSPORTHDR && is_icmp6_error(icmp6->icmp6_type) && - icmp_type != ICMP_PARAMETERPROB) { - // An ICMPv6 error we understand, one level deep. - // Translate the nested packet (the one that caused the error). - clat_packet_len = ipv6_packet(out, pos + 1, payload, payload_size); - } else if (icmp_type == ICMP_ECHO || icmp_type == ICMP_ECHOREPLY) { - // Ping packet. - icmp_targ->un.echo.id = icmp6->icmp6_id; - icmp_targ->un.echo.sequence = icmp6->icmp6_seq; - out[CLAT_POS_PAYLOAD].iov_base = (uint8_t *)payload; - out[CLAT_POS_PAYLOAD].iov_len = payload_size; - clat_packet_len = CLAT_POS_PAYLOAD + 1; - } else { - // Unknown type/code. The type/code conversion functions have already logged an error. - return 0; - } - - icmp_targ->checksum = 0; // Checksum field must be 0 when calculating checksum. - icmp_targ->checksum = packet_checksum(0, out, pos); - - return clat_packet_len; -} - -/* function: generic_packet - * takes a generic IP packet and sets it up for translation - * out - output packet - * pos - position in the output packet of the transport header - * payload - pointer to IP payload - * len - size of ip payload - * returns: the highest position in the output clat_packet that's filled in - */ -int generic_packet(clat_packet out, clat_packet_index pos, const uint8_t *payload, size_t len) { - out[pos].iov_len = 0; - out[CLAT_POS_PAYLOAD].iov_base = (uint8_t *)payload; - out[CLAT_POS_PAYLOAD].iov_len = len; - - return CLAT_POS_PAYLOAD + 1; -} - -/* function: udp_packet - * takes a udp packet and sets it up for translation - * out - output packet - * udp - pointer to udp header in packet - * old_sum - pseudo-header checksum of old header - * new_sum - pseudo-header checksum of new header - * len - size of ip payload - */ -int udp_packet(clat_packet out, clat_packet_index pos, const struct udphdr *udp, uint32_t old_sum, - uint32_t new_sum, size_t len) { - const uint8_t *payload; - size_t payload_size; - - if (len < sizeof(struct udphdr)) { - logmsg_dbg(ANDROID_LOG_ERROR, "udp_packet/(too small)"); - return 0; - } - - payload = (const uint8_t *)(udp + 1); - payload_size = len - sizeof(struct udphdr); - - return udp_translate(out, pos, udp, old_sum, new_sum, payload, payload_size); -} - -/* function: tcp_packet - * takes a tcp packet and sets it up for translation - * out - output packet - * tcp - pointer to tcp header in packet - * checksum - pseudo-header checksum - * len - size of ip payload - * returns: the highest position in the output clat_packet that's filled in - */ -int tcp_packet(clat_packet out, clat_packet_index pos, const struct tcphdr *tcp, uint32_t old_sum, - uint32_t new_sum, size_t len) { - const uint8_t *payload; - size_t payload_size, header_size; - - if (len < sizeof(struct tcphdr)) { - logmsg_dbg(ANDROID_LOG_ERROR, "tcp_packet/(too small)"); - return 0; - } - - if (tcp->doff < 5) { - logmsg_dbg(ANDROID_LOG_ERROR, "tcp_packet/tcp header length set to less than 5: %x", tcp->doff); - return 0; - } - - if ((size_t)tcp->doff * 4 > len) { - logmsg_dbg(ANDROID_LOG_ERROR, "tcp_packet/tcp header length set too large: %x", tcp->doff); - return 0; - } - - header_size = tcp->doff * 4; - payload = ((const uint8_t *)tcp) + header_size; - payload_size = len - header_size; - - return tcp_translate(out, pos, tcp, header_size, old_sum, new_sum, payload, payload_size); -} - -/* function: udp_translate - * common between ipv4/ipv6 - setup checksum and send udp packet - * out - output packet - * udp - udp header - * old_sum - pseudo-header checksum of old header - * new_sum - pseudo-header checksum of new header - * payload - tcp payload - * payload_size - size of payload - * returns: the highest position in the output clat_packet that's filled in - */ -int udp_translate(clat_packet out, clat_packet_index pos, const struct udphdr *udp, - uint32_t old_sum, uint32_t new_sum, const uint8_t *payload, size_t payload_size) { - struct udphdr *udp_targ = out[pos].iov_base; - - memcpy(udp_targ, udp, sizeof(struct udphdr)); - - out[pos].iov_len = sizeof(struct udphdr); - out[CLAT_POS_PAYLOAD].iov_base = (uint8_t *)payload; - out[CLAT_POS_PAYLOAD].iov_len = payload_size; - - if (udp_targ->check) { - udp_targ->check = ip_checksum_adjust(udp->check, old_sum, new_sum); - } else { - // Zero checksums are special. RFC 768 says, "An all zero transmitted checksum value means that - // the transmitter generated no checksum (for debugging or for higher level protocols that - // don't care)." However, in IPv6 zero UDP checksums were only permitted by RFC 6935 (2013). So - // for safety we recompute it. - udp_targ->check = 0; // Checksum field must be 0 when calculating checksum. - udp_targ->check = packet_checksum(new_sum, out, pos); - } - - // RFC 768: "If the computed checksum is zero, it is transmitted as all ones (the equivalent - // in one's complement arithmetic)." - if (!udp_targ->check) { - udp_targ->check = 0xffff; - } - - return CLAT_POS_PAYLOAD + 1; -} - -/* function: tcp_translate - * common between ipv4/ipv6 - setup checksum and send tcp packet - * out - output packet - * tcp - tcp header - * header_size - size of tcp header including options - * checksum - partial checksum covering ipv4/ipv6 header - * payload - tcp payload - * payload_size - size of payload - * returns: the highest position in the output clat_packet that's filled in - */ -int tcp_translate(clat_packet out, clat_packet_index pos, const struct tcphdr *tcp, - size_t header_size, uint32_t old_sum, uint32_t new_sum, const uint8_t *payload, - size_t payload_size) { - struct tcphdr *tcp_targ = out[pos].iov_base; - out[pos].iov_len = header_size; - - if (header_size > MAX_TCP_HDR) { - // A TCP header cannot be more than MAX_TCP_HDR bytes long because it's a 4-bit field that - // counts in 4-byte words. So this can never happen unless there is a bug in the caller. - logmsg(ANDROID_LOG_ERROR, "tcp_translate: header too long %d > %d, truncating", header_size, - MAX_TCP_HDR); - header_size = MAX_TCP_HDR; - } - - memcpy(tcp_targ, tcp, header_size); - - out[CLAT_POS_PAYLOAD].iov_base = (uint8_t *)payload; - out[CLAT_POS_PAYLOAD].iov_len = payload_size; - - tcp_targ->check = ip_checksum_adjust(tcp->check, old_sum, new_sum); - - return CLAT_POS_PAYLOAD + 1; -} - -// Weak symbol so we can override it in the unit test. -void send_rawv6(int fd, clat_packet out, int iov_len) __attribute__((weak)); - -void send_rawv6(int fd, clat_packet out, int iov_len) { - // A send on a raw socket requires a destination address to be specified even if the socket's - // protocol is IPPROTO_RAW. This is the address that will be used in routing lookups; the - // destination address in the packet header only affects what appears on the wire, not where the - // packet is sent to. - static struct sockaddr_in6 sin6 = { AF_INET6, 0, 0, { { { 0, 0, 0, 0 } } }, 0 }; - static struct msghdr msg = { - .msg_name = &sin6, - .msg_namelen = sizeof(sin6), - }; - - msg.msg_iov = out, msg.msg_iovlen = iov_len, - sin6.sin6_addr = ((struct ip6_hdr *)out[CLAT_POS_IPHDR].iov_base)->ip6_dst; - sendmsg(fd, &msg, 0); -} - -/* function: translate_packet - * takes a packet, translates it, and writes it to fd - * fd - fd to write translated packet to - * to_ipv6 - true if translating to ipv6, false if translating to ipv4 - * packet - packet - * packetsize - size of packet - */ -void translate_packet(int fd, int to_ipv6, const uint8_t *packet, size_t packetsize) { - int iov_len = 0; - - // Allocate buffers for all packet headers. - struct tun_pi tun_targ; - char iphdr[sizeof(struct ip6_hdr)]; - char fraghdr[sizeof(struct ip6_frag)]; - char transporthdr[MAX_TCP_HDR]; - char icmp_iphdr[sizeof(struct ip6_hdr)]; - char icmp_fraghdr[sizeof(struct ip6_frag)]; - char icmp_transporthdr[MAX_TCP_HDR]; - - // iovec of the packets we'll send. This gets passed down to the translation functions. - clat_packet out = { - { &tun_targ, 0 }, // Tunnel header. - { iphdr, 0 }, // IP header. - { fraghdr, 0 }, // Fragment header. - { transporthdr, 0 }, // Transport layer header. - { icmp_iphdr, 0 }, // ICMP error inner IP header. - { icmp_fraghdr, 0 }, // ICMP error fragmentation header. - { icmp_transporthdr, 0 }, // ICMP error transport layer header. - { NULL, 0 }, // Payload. No buffer, it's a pointer to the original payload. - }; - - if (to_ipv6) { - iov_len = ipv4_packet(out, CLAT_POS_IPHDR, packet, packetsize); - if (iov_len > 0) { - send_rawv6(fd, out, iov_len); - } - } else { - iov_len = ipv6_packet(out, CLAT_POS_IPHDR, packet, packetsize); - if (iov_len > 0) { - fill_tun_header(&tun_targ, ETH_P_IP); - out[CLAT_POS_TUNHDR].iov_len = sizeof(tun_targ); - writev(fd, out, iov_len); - } - } -} diff --git a/translate.h b/translate.h deleted file mode 100644 index 0e520f7..0000000 --- a/translate.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2011 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * translate.h - translate from one version of ip to another - */ -#ifndef __TRANSLATE_H__ -#define __TRANSLATE_H__ - -#include <linux/icmp.h> -#include <linux/if_tun.h> -#include <netinet/icmp6.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/ip6.h> -#include <netinet/ip_icmp.h> -#include <netinet/tcp.h> -#include <netinet/udp.h> - -#include "clatd.h" -#include "common.h" - -#define MAX_TCP_HDR (15 * 4) // Data offset field is 4 bits and counts in 32-bit words. - -// Calculates the checksum over all the packet components starting from pos. -uint16_t packet_checksum(uint32_t checksum, clat_packet packet, clat_packet_index pos); - -// Returns the total length of the packet components after pos. -uint16_t packet_length(clat_packet packet, clat_packet_index pos); - -// Returns true iff the given IPv6 address is in the plat subnet. -int is_in_plat_subnet(const struct in6_addr *addr6); - -// Functions to create tun, IPv4, and IPv6 headers. -void fill_tun_header(struct tun_pi *tun_header, uint16_t proto); -void fill_ip_header(struct iphdr *ip_targ, uint16_t payload_len, uint8_t protocol, - const struct ip6_hdr *old_header); -void fill_ip6_header(struct ip6_hdr *ip6, uint16_t payload_len, uint8_t protocol, - const struct iphdr *old_header); - -// Translate and send packets. -void translate_packet(int fd, int to_ipv6, const uint8_t *packet, size_t packetsize); - -// Translate IPv4 and IPv6 packets. -int ipv4_packet(clat_packet out, clat_packet_index pos, const uint8_t *packet, size_t len); -int ipv6_packet(clat_packet out, clat_packet_index pos, const uint8_t *packet, size_t len); - -// Deal with fragmented packets. -size_t maybe_fill_frag_header(struct ip6_frag *frag_hdr, struct ip6_hdr *ip6_targ, - const struct iphdr *old_header); -uint8_t parse_frag_header(const struct ip6_frag *frag_hdr, struct iphdr *ip_targ); - -// Deal with fragmented packets. -size_t maybe_fill_frag_header(struct ip6_frag *frag_hdr, struct ip6_hdr *ip6_targ, - const struct iphdr *old_header); -uint8_t parse_frag_header(const struct ip6_frag *frag_hdr, struct iphdr *ip_targ); - -// Translate ICMP packets. -int icmp_to_icmp6(clat_packet out, clat_packet_index pos, const struct icmphdr *icmp, - uint32_t checksum, const uint8_t *payload, size_t payload_size); -int icmp6_to_icmp(clat_packet out, clat_packet_index pos, const struct icmp6_hdr *icmp6, - const uint8_t *payload, size_t payload_size); - -// Translate generic IP packets. -int generic_packet(clat_packet out, clat_packet_index pos, const uint8_t *payload, size_t len); - -// Translate TCP and UDP packets. -int tcp_packet(clat_packet out, clat_packet_index pos, const struct tcphdr *tcp, uint32_t old_sum, - uint32_t new_sum, size_t len); -int udp_packet(clat_packet out, clat_packet_index pos, const struct udphdr *udp, uint32_t old_sum, - uint32_t new_sum, size_t len); - -int tcp_translate(clat_packet out, clat_packet_index pos, const struct tcphdr *tcp, - size_t header_size, uint32_t old_sum, uint32_t new_sum, const uint8_t *payload, - size_t payload_size); -int udp_translate(clat_packet out, clat_packet_index pos, const struct udphdr *udp, - uint32_t old_sum, uint32_t new_sum, const uint8_t *payload, size_t payload_size); - -#endif /* __TRANSLATE_H__ */ |