From bd22bc6ebe2bf9672e2f03ad2be3c4764f26ce7d Mon Sep 17 00:00:00 2001 From: Hansen Kurli Date: Wed, 8 Nov 2023 20:25:22 +0800 Subject: Remove mtpd Legacy Vpn is removed. Bug: 161776767 Test: m Change-Id: I201193add59b0f17ec3e5f817039a184234f0af3 --- Android.bp | 51 ---- METADATA | 3 - MODULE_LICENSE_APACHE2 | 0 NOTICE | 190 -------------- OWNERS | 2 - l2tp.c | 683 ------------------------------------------------- mtpd.c | 473 ---------------------------------- mtpd.h | 97 ------- mtpd.rc | 8 - pptp.c | 583 ----------------------------------------- 10 files changed, 2090 deletions(-) delete mode 100644 Android.bp delete mode 100644 METADATA delete mode 100644 MODULE_LICENSE_APACHE2 delete mode 100644 NOTICE delete mode 100644 OWNERS delete mode 100644 l2tp.c delete mode 100644 mtpd.c delete mode 100644 mtpd.h delete mode 100644 mtpd.rc delete mode 100644 pptp.c diff --git a/Android.bp b/Android.bp deleted file mode 100644 index 9efa325..0000000 --- a/Android.bp +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2016 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. - -package { - default_applicable_licenses: ["external_mtpd_license"], -} - -// Added automatically by a large-scale-change -// See: http://go/android-license-faq -license { - name: "external_mtpd_license", - visibility: [":__subpackages__"], - license_kinds: [ - "SPDX-license-identifier-Apache-2.0", - ], - license_text: [ - "NOTICE", - ], -} - -cc_binary { - name: "mtpd", - srcs: [ - "mtpd.c", - "l2tp.c", - "pptp.c" - ], - shared_libs: [ - "libcrypto", - "libcutils", - "liblog", - "libnetd_client", - ], - cflags: [ - "-DANDROID_CHANGES", - "-Wall", - "-Werror", - ], - init_rc: ["mtpd.rc"], -} 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 diff --git a/NOTICE b/NOTICE deleted file mode 100644 index 64aaa8d..0000000 --- a/NOTICE +++ /dev/null @@ -1,190 +0,0 @@ - - Copyright (c) 2009, 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. - - 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 - diff --git a/OWNERS b/OWNERS deleted file mode 100644 index c24680e..0000000 --- a/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -set noparent -file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking diff --git a/l2tp.c b/l2tp.c deleted file mode 100644 index ae6088d..0000000 --- a/l2tp.c +++ /dev/null @@ -1,683 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -/* - * Implementation of L2TP Access Concentrator (RFC 2661). The following code - * only handles control packets. Data packets are handled by kernel driver: - * - PX_PROTO_OL2TP (upstream impl.), if it's enabled in kernel - * - or PX_PROTO_OLAC (Android impl.), if upstream implementation is not - * available / not enabled. It will be removed in new Android kernels. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mtpd.h" - -/* To avoid unnecessary endianness conversions, tunnels, sessions, attributes, - * and values are all accessed in network order. */ - -/* 0 is reserved. We put ACK here just for convenience. */ -enum l2tp_message { - ACK = 0, - SCCRQ = 1, - SCCRP = 2, - SCCCN = 3, - STOPCCN = 4, - HELLO = 6, - OCRQ = 7, - OCRP = 8, - OCCN = 9, - ICRQ = 10, - ICRP = 11, - ICCN = 12, - CDN = 14, - WEN = 15, - SLI = 16, - MESSAGE_MAX = 16, -}; - -static char *messages[] = { - "ACK", "SCCRQ", "SCCRP", "SCCCN", "STOPCCN", NULL, "HELLO", "OCRQ", - "OCRP", "OCCN", "ICRQ", "ICRP", "ICCN", NULL, "CDN", "WEN", "SLI", -}; - -/* This is incomplete. Only those we used are listed here. */ -#define RESULT_CODE htons(1) -#define PROTOCOL_VERSION htons(2) -#define FRAMING_CAPABILITIES htons(3) -#define HOST_NAME htons(7) -#define ASSIGNED_TUNNEL htons(9) -#define WINDOW_SIZE htons(10) -#define CHALLENGE htons(11) -#define CHALLENGE_RESPONSE htons(13) -#define ASSIGNED_SESSION htons(14) -#define CALL_SERIAL_NUMBER htons(15) -#define FRAMING_TYPE htons(19) -#define CONNECT_SPEED htons(24) -#define RANDOM_VECTOR htons(36) - -#define MESSAGE_FLAG 0xC802 -#define MESSAGE_MASK 0xCB0F -#define ATTRIBUTE_FLAG(length) (0x8006 + (length)) -#define ATTRIBUTE_LENGTH(flag) (0x03FF & (flag)) -#define ATTRIBUTE_HIDDEN(flag) (0x4000 & (flag)) - -#define ACK_SIZE 12 -#define MESSAGE_HEADER_SIZE 20 -#define ATTRIBUTE_HEADER_SIZE 6 -#define MAX_ATTRIBUTE_SIZE 1024 - -static __be16 local_tunnel; -static __be16 local_session; -static uint16_t local_sequence; -static __be16 remote_tunnel; -static __be16 remote_session; -static uint16_t remote_sequence; - -static uint16_t state; -static int acknowledged; - -#define RANDOM_DEVICE "/dev/urandom" -#define CHALLENGE_SIZE 32 - -static char *secret; -static int secret_length; -static uint8_t challenge[CHALLENGE_SIZE]; - -/* According to RFC 2661 page 46, an exponential backoff strategy is required - * for retransmission. However, it might waste too much time waiting for IPsec - * negotiation. Here we use the same interval to keep things simple. */ -#define TIMEOUT_INTERVAL 2000 - -#define MAX_PACKET_LENGTH 2048 - -static struct packet { - int message; - int length; - uint8_t buffer[MAX_PACKET_LENGTH] __attribute__((aligned(4))); -} incoming, outgoing; - -struct attribute { - uint16_t flag; - uint16_t vendor; - uint16_t type; - uint8_t value[1]; -} __attribute__((packed)); - -static void set_message(uint16_t session, uint16_t message) -{ - uint16_t *p = (uint16_t *)outgoing.buffer; - p[0] = htons(MESSAGE_FLAG); - /* p[1] will be filled in send_packet(). */ - p[2] = remote_tunnel; - p[3] = session; - p[4] = htons(local_sequence); - p[5] = htons(remote_sequence); - p[6] = htons(ATTRIBUTE_FLAG(2)); - p[7] = 0; - p[8] = 0; - p[9] = htons(message); - outgoing.message = message; - outgoing.length = MESSAGE_HEADER_SIZE; - ++local_sequence; -} - -static void add_attribute_raw(uint16_t type, void *value, int size) -{ - struct attribute *p = (struct attribute *)&outgoing.buffer[outgoing.length]; - p->flag = htons(ATTRIBUTE_FLAG(size)); - p->vendor = 0; - p->type = type; - memcpy(&p->value, value, size); - outgoing.length += ATTRIBUTE_HEADER_SIZE + size; -} - -static void add_attribute_u16(uint16_t attribute, uint16_t value) -{ - add_attribute_raw(attribute, &value, sizeof(uint16_t)); -} - -static void add_attribute_u32(uint16_t attribute, uint32_t value) -{ - add_attribute_raw(attribute, &value, sizeof(uint32_t)); -} - -static void send_packet() -{ - uint16_t *p = (uint16_t *)outgoing.buffer; - p[1] = htons(outgoing.length); - send(the_socket, outgoing.buffer, outgoing.length, 0); - acknowledged = 0; -} - -static void send_ack() -{ - uint16_t buffer[6] = { - htons(MESSAGE_FLAG), htons(ACK_SIZE), remote_tunnel, 0, - htons(local_sequence), htons(remote_sequence), - }; - send(the_socket, buffer, ACK_SIZE, 0); -} - -static int recv_packet(uint16_t *session) -{ - uint16_t *p = (uint16_t *)incoming.buffer; - - incoming.length = recv(the_socket, incoming.buffer, MAX_PACKET_LENGTH, 0); - if (incoming.length == -1) { - if (errno == EINTR) { - return 0; - } - log_print(FATAL, "Recv() %s", strerror(errno)); - exit(NETWORK_ERROR); - } - - /* We only handle packets in our tunnel. */ - if ((incoming.length != ACK_SIZE && incoming.length < MESSAGE_HEADER_SIZE) - || (p[0] & htons(MESSAGE_MASK)) != htons(MESSAGE_FLAG) || - ntohs(p[1]) != incoming.length || p[2] != local_tunnel) { - return 0; - } - - if (incoming.length == ACK_SIZE) { - incoming.message = ACK; - } else if (p[6] == htons(ATTRIBUTE_FLAG(2)) && !p[7] && !p[8]) { - incoming.message = ntohs(p[9]); - } else { - return 0; - } - - /* Check if the packet is duplicated and send ACK if necessary. */ - if ((uint16_t)(ntohs(p[4]) - remote_sequence) > 32767) { - if (incoming.message != ACK) { - send_ack(); - } - return 0; - } - - if (ntohs(p[5]) == local_sequence) { - acknowledged = 1; - } - - /* Our sending and receiving window sizes are both 1. Thus we only handle - * this packet if it is their next one and they received our last one. */ - if (ntohs(p[4]) != remote_sequence || !acknowledged) { - return 0; - } - *session = p[3]; - if (incoming.message != ACK) { - ++remote_sequence; - } - return 1; -} - -static int get_attribute_raw(uint16_t type, void *value, int size) -{ - int offset = MESSAGE_HEADER_SIZE; - uint8_t *vector = NULL; - int vector_length = 0; - - while (incoming.length >= offset + ATTRIBUTE_HEADER_SIZE) { - struct attribute *p = (struct attribute *)&incoming.buffer[offset]; - uint16_t flag = ntohs(p->flag); - int length = ATTRIBUTE_LENGTH(flag); - - offset += length; - length -= ATTRIBUTE_HEADER_SIZE; - if (length < 0 || offset > incoming.length) { - break; - } - if (p->vendor) { - continue; - } - if (p->type != type) { - if (p->type == RANDOM_VECTOR && !ATTRIBUTE_HIDDEN(flag)) { - vector = p->value; - vector_length = length; - } - continue; - } - - if (!ATTRIBUTE_HIDDEN(flag)) { - if (size > length) { - size = length; - } - memcpy(value, p->value, size); - return size; - } - - if (!secret || !vector || length < 2) { - return 0; - } else { - uint8_t buffer[MAX_ATTRIBUTE_SIZE]; - uint8_t hash[MD5_DIGEST_LENGTH]; - MD5_CTX ctx; - int i; - - MD5_Init(&ctx); - MD5_Update(&ctx, &type, sizeof(uint16_t)); - MD5_Update(&ctx, secret, secret_length); - MD5_Update(&ctx, vector, vector_length); - MD5_Final(hash, &ctx); - - for (i = 0; i < length; ++i) { - int j = i % MD5_DIGEST_LENGTH; - if (i && !j) { - MD5_Init(&ctx); - MD5_Update(&ctx, secret, secret_length); - MD5_Update(&ctx, &p->value[i - MD5_DIGEST_LENGTH], - MD5_DIGEST_LENGTH); - MD5_Final(hash, &ctx); - } - buffer[i] = p->value[i] ^ hash[j]; - } - - length = buffer[0] << 8 | buffer[1]; - if (length > i - 2) { - return 0; - } - if (size > length) { - size = length; - } - memcpy(value, &buffer[2], size); - return size; - } - } - return 0; -} - -static int get_attribute_u16(uint16_t type, uint16_t *value) -{ - return get_attribute_raw(type, value, sizeof(uint16_t)) == sizeof(uint16_t); -} - -static int l2tp_connect(char **arguments) -{ - create_socket(AF_INET, SOCK_DGRAM, arguments[0], arguments[1]); - - while (!local_tunnel) { - local_tunnel = random(); - } - - log_print(DEBUG, "Sending SCCRQ (local_tunnel = %u)", - (unsigned)ntohs(local_tunnel)); - state = SCCRQ; - set_message(0, SCCRQ); - add_attribute_u16(PROTOCOL_VERSION, htons(0x0100)); - add_attribute_raw(HOST_NAME, "anonymous", 9); - add_attribute_u32(FRAMING_CAPABILITIES, htonl(3)); - add_attribute_u16(ASSIGNED_TUNNEL, local_tunnel); - add_attribute_u16(WINDOW_SIZE, htons(1)); - - if (arguments[2][0]) { - int fd = open(RANDOM_DEVICE, O_RDONLY); - if (fd == -1 || read(fd, challenge, CHALLENGE_SIZE) != CHALLENGE_SIZE) { - log_print(FATAL, "Cannot read %s", RANDOM_DEVICE); - exit(SYSTEM_ERROR); - } - close(fd); - - add_attribute_raw(CHALLENGE, challenge, CHALLENGE_SIZE); - secret = arguments[2]; - secret_length = strlen(arguments[2]); - } - - send_packet(); - return TIMEOUT_INTERVAL; -} - -/** - * Check if upstream kernel implementation of L2TP should be used. - * - * @return true If upstream L2TP should be used, which is the case if - * the obsolete OLAC feature is not available. - */ -static bool check_ol2tp(void) -{ - int fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OLAC); - - if (fd < 0) { - return true; - } else { - close(fd); - return false; - } -} - -/** - * Create OLAC session. - * - * @deprecated It will be removed soon in favor of upstream OL2TP. - * - * @return PPPoX socket file descriptor - */ -static int create_pppox_olac(void) -{ - int pppox; - - log_print(WARNING, "Using deprecated OLAC protocol. " - "Its support will be removed soon. " - "Please enable OL2TP support in your kernel"); - - log_print(INFO, "Creating PPPoX socket"); - pppox = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OLAC); - - if (pppox == -1) { - log_print(FATAL, "Socket() %s", strerror(errno)); - exit(SYSTEM_ERROR); - } else { - struct sockaddr_pppolac address = { - .sa_family = AF_PPPOX, - .sa_protocol = PX_PROTO_OLAC, - .udp_socket = the_socket, - .local = {.tunnel = local_tunnel, .session = local_session}, - .remote = {.tunnel = remote_tunnel, .session = remote_session}, - }; - if (connect(pppox, (struct sockaddr *)&address, sizeof(address))) { - log_print(FATAL, "Connect() %s", strerror(errno)); - exit(SYSTEM_ERROR); - } - } - return pppox; -} - -/** - * Create OL2TP tunnel and session. - * - * @param[out] tfd Will contain tunnel socket file descriptor - * @param[out] sfd Will contain session socket file descriptor - */ -static void create_pppox_ol2tp(int *tfd, int *sfd) -{ - int tunnel_fd; - int session_fd; - struct sockaddr_pppol2tp tunnel_sa; - struct sockaddr_pppol2tp session_sa; - - log_print(INFO, "Creating PPPoX tunnel socket..."); - tunnel_fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP); - if (tunnel_fd < 0) { - log_print(FATAL, "Tunnel socket(): %s", strerror(errno)); - exit(SYSTEM_ERROR); - } - - memset(&tunnel_sa, 0, sizeof(tunnel_sa)); - tunnel_sa.sa_family = AF_PPPOX; - tunnel_sa.sa_protocol = PX_PROTO_OL2TP; - tunnel_sa.pppol2tp.fd = the_socket; /* UDP socket */ - tunnel_sa.pppol2tp.s_tunnel = ntohs(local_tunnel); - tunnel_sa.pppol2tp.s_session = 0; /* special case: mgmt socket */ - tunnel_sa.pppol2tp.d_tunnel = ntohs(remote_tunnel); - tunnel_sa.pppol2tp.d_session = 0; /* special case: mgmt socket */ - - log_print(INFO, "Connecting to tunnel socket..."); - if (connect(tunnel_fd, (struct sockaddr *)&tunnel_sa, - sizeof(tunnel_sa))) { - log_print(FATAL, "Tunnel connect(): %s", strerror(errno)); - exit(SYSTEM_ERROR); - } - - log_print(INFO, "Creating PPPoX session socket..."); - session_fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP); - if (session_fd < 0) { - log_print(FATAL, "Session socket(): %s", strerror(errno)); - exit(SYSTEM_ERROR); - } - - memset(&session_sa, 0, sizeof(session_sa)); - session_sa.sa_family = AF_PPPOX; - session_sa.sa_protocol = PX_PROTO_OL2TP; - session_sa.pppol2tp.fd = the_socket; - session_sa.pppol2tp.s_tunnel = ntohs(local_tunnel); - session_sa.pppol2tp.s_session = ntohs(local_session); - session_sa.pppol2tp.d_tunnel = ntohs(remote_tunnel); - session_sa.pppol2tp.d_session = ntohs(remote_session); - - log_print(INFO, "Connecting to session socket..."); - if (connect(session_fd, (struct sockaddr *)&session_sa, - sizeof(session_sa))) { - log_print(FATAL, "Session connect(): %s", strerror(errno)); - exit(SYSTEM_ERROR); - } - - *tfd = tunnel_fd; - *sfd = session_fd; -} - -static uint8_t *compute_response(uint8_t type, void *challenge, int size) -{ - static uint8_t response[MD5_DIGEST_LENGTH]; - MD5_CTX ctx; - MD5_Init(&ctx); - MD5_Update(&ctx, &type, sizeof(uint8_t)); - MD5_Update(&ctx, secret, secret_length); - MD5_Update(&ctx, challenge, size); - MD5_Final(response, &ctx); - return response; -} - -static bool verify_challenge() -{ - if (secret) { - uint8_t response[MD5_DIGEST_LENGTH]; - if (get_attribute_raw(CHALLENGE_RESPONSE, response, MD5_DIGEST_LENGTH) - != MD5_DIGEST_LENGTH) { - return false; - } - return !memcmp(compute_response(SCCRP, challenge, CHALLENGE_SIZE), - response, MD5_DIGEST_LENGTH); - } - return true; -} - -static void answer_challenge() -{ - if (secret) { - uint8_t challenge[MAX_ATTRIBUTE_SIZE]; - int size = get_attribute_raw(CHALLENGE, challenge, MAX_ATTRIBUTE_SIZE); - if (size > 0) { - uint8_t *response = compute_response(SCCCN, challenge, size); - add_attribute_raw(CHALLENGE_RESPONSE, response, MD5_DIGEST_LENGTH); - } - } -} - -static int l2tp_process() -{ - uint16_t sequence = local_sequence; - __be16 tunnel = 0; - __be16 session = 0; - - if (!recv_packet(&session)) { - return acknowledged ? 0 : TIMEOUT_INTERVAL; - } - - /* Here is the fun part. We always try to protect our tunnel and session - * from being closed even if we received unexpected messages. */ - switch(incoming.message) { - case SCCRP: - if (state == SCCRQ) { - if (get_attribute_u16(ASSIGNED_TUNNEL, &tunnel) && tunnel && - verify_challenge()) { - remote_tunnel = tunnel; - log_print(DEBUG, "Received SCCRP (remote_tunnel = %u) -> " - "Sending SCCCN", (unsigned)ntohs(remote_tunnel)); - state = SCCCN; - set_message(0, SCCCN); - answer_challenge(); - break; - } - log_print(DEBUG, "Received SCCRP without %s", tunnel ? - "valid challenge response" : "assigned tunnel"); - log_print(ERROR, "Protocol error"); - return tunnel ? -CHALLENGE_FAILED : -PROTOCOL_ERROR; - } - break; - - case ICRP: - if (state == ICRQ && session == local_session) { - if (get_attribute_u16(ASSIGNED_SESSION, &session) && session) { - remote_session = session; - log_print(DEBUG, "Received ICRP (remote_session = %u) -> " - "Sending ICCN", (unsigned)ntohs(remote_session)); - state = ICCN; - set_message(remote_session, ICCN); - add_attribute_u32(CONNECT_SPEED, htonl(100000000)); - add_attribute_u32(FRAMING_TYPE, htonl(3)); - break; - } - log_print(DEBUG, "Received ICRP without assigned session"); - log_print(ERROR, "Protocol error"); - return -PROTOCOL_ERROR; - } - break; - - case STOPCCN: - log_print(DEBUG, "Received STOPCCN"); - log_print(INFO, "Remote server hung up"); - state = STOPCCN; - return -REMOTE_REQUESTED; - - case CDN: - if (session && session == local_session) { - log_print(DEBUG, "Received CDN (local_session = %u)", - (unsigned)ntohs(local_session)); - log_print(INFO, "Remote server hung up"); - return -REMOTE_REQUESTED; - } - break; - - case ACK: - case HELLO: - case WEN: - case SLI: - /* These are harmless, so we just treat them in the same way. */ - if (state == SCCCN) { - while (!local_session) { - local_session = random(); - } - log_print(DEBUG, "Received %s -> Sending ICRQ (local_session = " - "%u)", messages[incoming.message], - (unsigned)ntohs(local_session)); - log_print(INFO, "Tunnel established"); - state = ICRQ; - set_message(0, ICRQ); - add_attribute_u16(ASSIGNED_SESSION, local_session); - add_attribute_u32(CALL_SERIAL_NUMBER, random()); - break; - } - - if (incoming.message == ACK) { - log_print(DEBUG, "Received ACK"); - } else { - log_print(DEBUG, "Received %s -> Sending ACK", - messages[incoming.message]); - send_ack(); - } - - if (state == ICCN) { - log_print(INFO, "Session established"); - state = ACK; - - if (check_ol2tp()) { - int tunnel_fd, session_fd; - - create_pppox_ol2tp(&tunnel_fd, &session_fd); - start_pppd_ol2tp(tunnel_fd, session_fd, - ntohs(remote_tunnel), - ntohs(remote_session)); - } else { - start_pppd(create_pppox_olac()); - } - } - return 0; - - case ICRQ: - case OCRQ: - /* Since we run pppd as a client, it does not makes sense to - * accept ICRQ or OCRQ. Always send CDN with a proper error. */ - if (get_attribute_u16(ASSIGNED_SESSION, &session) && session) { - log_print(DEBUG, "Received %s (remote_session = %u) -> " - "Sending CDN", messages[incoming.message], - (unsigned)ntohs(session)); - set_message(session, CDN); - add_attribute_u32(RESULT_CODE, htonl(0x00020006)); - add_attribute_u16(ASSIGNED_SESSION, 0); - } - break; - } - - if (sequence != local_sequence) { - send_packet(); - return TIMEOUT_INTERVAL; - } - - /* We reach here if we got an unexpected message. Log it and send ACK. */ - if (incoming.message > MESSAGE_MAX || !messages[incoming.message]) { - log_print(DEBUG, "Received UNKNOWN %d -> Sending ACK anyway", - incoming.message); - } else { - log_print(DEBUG, "Received UNEXPECTED %s -> Sending ACK anyway", - messages[incoming.message]); - } - send_ack(); - return 0; -} - -static int l2tp_timeout() -{ - if (acknowledged) { - return 0; - } - log_print(DEBUG, "Timeout -> Sending %s", messages[outgoing.message]); - send(the_socket, outgoing.buffer, outgoing.length, 0); - return TIMEOUT_INTERVAL; -} - -static void l2tp_shutdown() -{ - if (state != STOPCCN) { - log_print(DEBUG, "Sending STOPCCN"); - set_message(0, STOPCCN); - add_attribute_u16(ASSIGNED_TUNNEL, local_tunnel); - add_attribute_u16(RESULT_CODE, htons(6)); - send_packet(); - } -} - -struct protocol l2tp = { - .name = "l2tp", - .arguments = 3, - .usage = " ", - .connect = l2tp_connect, - .process = l2tp_process, - .timeout = l2tp_timeout, - .shutdown = l2tp_shutdown, -}; diff --git a/mtpd.c b/mtpd.c deleted file mode 100644 index ac724ac..0000000 --- a/mtpd.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef ANDROID_CHANGES -#include -#include -#endif - -#include "mtpd.h" -#include "NetdClient.h" - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) -/* Characters count in string with max value of unsigned type t */ -#define TYPE_STRLEN_U(t) ((((sizeof(t) * CHAR_BIT) * 1233) >> 12) + 1) -/* Length of string with max file descriptor value */ -#define FD_MAX_LEN TYPE_STRLEN_U(int) - -int the_socket = -1; - -extern struct protocol l2tp; -extern struct protocol pptp; -static struct protocol *protocols[] = {&l2tp, &pptp, NULL}; -static struct protocol *the_protocol; - -static char *interface; -static int pppd_argc; -static char **pppd_argv; -static pid_t pppd_pid; - -/* We redirect signals to a pipe in order to prevent race conditions. */ -static int signals[2]; - -static void interrupt(int signal) -{ - write(signals[1], &signal, sizeof(int)); -} - -static int initialize(int argc, char **argv) -{ - int i; - - for (i = 0; protocols[i]; ++i) { - struct protocol *p = protocols[i]; - if (argc - 3 >= p->arguments && !strcmp(argv[2], p->name)) { - log_print(INFO, "Using protocol %s", p->name); - the_protocol = p; - break; - } - } - - if (!the_protocol) { - printf("Usages:\n"); - for (i = 0; protocols[i]; ++i) { - struct protocol *p = protocols[i]; - printf(" %s interface %s %s pppd-arguments\n", - argv[0], p->name, p->usage); - } - exit(0); - } - - interface = argv[1]; - pppd_argc = argc - 3 - the_protocol->arguments; - pppd_argv = &argv[3 + the_protocol->arguments]; - return the_protocol->connect(&argv[3]); -} - -static void stop_pppd() -{ - if (pppd_pid) { - int status; - log_print(INFO, "Sending signal to pppd (pid = %d)", pppd_pid); - kill(pppd_pid, SIGTERM); - waitpid(pppd_pid, &status, 0); - pppd_pid = 0; - } -} - -#ifdef ANDROID_CHANGES - -static int android_get_control_and_arguments(int *argc, char ***argv) -{ - static char *args[32]; - int control; - int i; - - if ((i = android_get_control_socket("mtpd")) == -1) { - return -1; - } - log_print(DEBUG, "Waiting for control socket"); - if (listen(i, 1) == -1 || (control = accept(i, NULL, 0)) == -1) { - log_print(FATAL, "Cannot get control socket"); - exit(SYSTEM_ERROR); - } - close(i); - fcntl(control, F_SETFD, FD_CLOEXEC); - - args[0] = (*argv)[0]; - for (i = 1; i < 32; ++i) { - unsigned char bytes[2]; - if (recv(control, &bytes[0], 1, 0) != 1 || - recv(control, &bytes[1], 1, 0) != 1) { - log_print(FATAL, "Cannot get argument length"); - exit(SYSTEM_ERROR); - } else { - int length = bytes[0] << 8 | bytes[1]; - int offset = 0; - - if (length == 0xFFFF) { - break; - } - args[i] = malloc(length + 1); - while (offset < length) { - int n = recv(control, &args[i][offset], length - offset, 0); - if (n > 0) { - offset += n; - } else { - log_print(FATAL, "Cannot get argument value"); - exit(SYSTEM_ERROR); - } - } - args[i][length] = 0; - } - } - log_print(DEBUG, "Received %d arguments", i - 1); - - *argc = i; - *argv = args; - return control; -} - -#endif - -int main(int argc, char **argv) -{ - struct pollfd pollfds[3]; - int control = -1; - int timeout; - int status; - -#ifdef ANDROID_CHANGES - control = android_get_control_and_arguments(&argc, &argv); - shutdown(control, SHUT_WR); -#endif - - srandom(time(NULL)); - - if (pipe(signals) == -1) { - log_print(FATAL, "Pipe() %s", strerror(errno)); - exit(SYSTEM_ERROR); - } - fcntl(signals[0], F_SETFD, FD_CLOEXEC); - fcntl(signals[1], F_SETFD, FD_CLOEXEC); - - timeout = initialize(argc, argv); - - signal(SIGHUP, interrupt); - signal(SIGINT, interrupt); - signal(SIGTERM, interrupt); - signal(SIGCHLD, interrupt); - signal(SIGPIPE, SIG_IGN); - atexit(stop_pppd); - - pollfds[0].fd = the_socket; - pollfds[0].events = POLLIN; - pollfds[1].fd = signals[0]; - pollfds[1].events = POLLIN; - pollfds[2].fd = control; - pollfds[2].events = 0; - - while (timeout >= 0) { - if (poll(pollfds, 3, timeout ? timeout : -1) == -1 && errno != EINTR) { - log_print(FATAL, "Poll() %s", strerror(errno)); - exit(SYSTEM_ERROR); - } - if (pollfds[1].revents) { - break; - } - if (pollfds[2].revents) { - interrupt(SIGTERM); - } - timeout = pollfds[0].revents ? - the_protocol->process() : the_protocol->timeout(); -#ifdef ANDROID_CHANGES - if (!access("/data/misc/vpn/abort", F_OK)) { - interrupt(SIGTERM); - } - if (!timeout) { - timeout = 5000; - } -#endif - } - - if (timeout < 0) { - status = -timeout; - } else { - int signal; - read(signals[0], &signal, sizeof(int)); - log_print(INFO, "Received signal %d", signal); - if (signal == SIGCHLD && waitpid(pppd_pid, &status, WNOHANG) == pppd_pid - && WIFEXITED(status)) { - status = WEXITSTATUS(status); - log_print(INFO, "Pppd is terminated (status = %d)", status); - status += PPPD_EXITED; - pppd_pid = 0; - } else { - status = USER_REQUESTED; - } - } - - stop_pppd(); - the_protocol->shutdown(); - log_print(INFO, "Mtpd is terminated (status = %d)", status); - return status; -} - -void log_print(int level, char *format, ...) -{ - if (level >= 0 && level <= LOG_MAX) { -#ifdef ANDROID_CHANGES - static int levels[5] = { - ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, - ANDROID_LOG_ERROR, ANDROID_LOG_FATAL - }; - va_list ap; - va_start(ap, format); - __android_log_vprint(levels[level], "mtpd", format, ap); - va_end(ap); -#else - static char *levels = "DIWEF"; - va_list ap; - fprintf(stderr, "%c: ", levels[level]); - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); - fputc('\n', stderr); -#endif - } -} - -void create_socket(int family, int type, char *server, char *port) -{ - struct addrinfo hints = { - .ai_flags = AI_NUMERICSERV, - .ai_family = family, - .ai_socktype = type, - }; - struct addrinfo *records; - struct addrinfo *r; - int error; - - log_print(INFO, "Connecting to %s port %s via %s", server, port, interface); - - error = getaddrinfo(server, port, &hints, &records); - if (error) { - log_print(FATAL, "Getaddrinfo() %s", (error == EAI_SYSTEM) ? - strerror(errno) : gai_strerror(error)); - exit(NETWORK_ERROR); - } - - for (r = records; r; r = r->ai_next) { - int s = socket(r->ai_family, r->ai_socktype, r->ai_protocol); - if (!setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, interface, - strlen(interface)) && !connect(s, r->ai_addr, r->ai_addrlen)) { - the_socket = s; - break; - } - close(s); - } - - freeaddrinfo(records); - - if (the_socket == -1) { - log_print(FATAL, "Connect() %s", strerror(errno)); - exit(NETWORK_ERROR); - } - -#ifdef ANDROID_CHANGES - protectFromVpn(the_socket); -#endif - - fcntl(the_socket, F_SETFD, FD_CLOEXEC); - log_print(INFO, "Connection established (socket = %d)", the_socket); -} - -void start_pppd(int pppox) -{ - if (pppd_pid) { - log_print(WARNING, "Pppd is already started (pid = %d)", pppd_pid); - close(pppox); - return; - } - - log_print(INFO, "Starting pppd (pppox = %d)", pppox); - - pppd_pid = fork(); - if (pppd_pid < 0) { - log_print(FATAL, "Fork() %s", strerror(errno)); - exit(SYSTEM_ERROR); - } - - if (!pppd_pid) { - char *args[pppd_argc + 5]; - char number[FD_MAX_LEN + 1]; - - snprintf(number, FD_MAX_LEN + 1, "%d", pppox); - args[0] = "pppd"; - args[1] = "nodetach"; - args[2] = "pppox"; - args[3] = number; - memcpy(&args[4], pppd_argv, sizeof(char *) * pppd_argc); - args[4 + pppd_argc] = NULL; - - execvp("pppd", args); - log_print(FATAL, "Exec() %s", strerror(errno)); - exit(SYSTEM_ERROR); /* Pretending a fatal error in pppd. */ - } - - log_print(INFO, "Pppd started (pid = %d)", pppd_pid); - close(pppox); -} - -/** - * Start pppd daemon with pppol2tp-android plugin. - * - * @param tunnel_fd Tunnel socket file descriptor - * @param session_fd Session socket file descriptor - * @param tunnel_id Tunnel ID; must be in host byte order - * @param session_id Session ID; must be in host byte order - */ -void start_pppd_ol2tp(int tunnel_fd, int session_fd, int tunnel_id, - int session_id) -{ - if (pppd_pid) { - log_print(WARNING, "Pppd is already started (pid = %d)", pppd_pid); - goto ret; - } - - log_print(INFO, "Starting pppd (tunnel_fd = %d, session_fd = %d)", - tunnel_fd, session_fd); - - pppd_pid = fork(); - if (pppd_pid < 0) { - log_print(FATAL, "Fork() %s", strerror(errno)); - exit(SYSTEM_ERROR); - } - - if (!pppd_pid) { - char tunnel_fd_str[FD_MAX_LEN + 1]; - char session_fd_str[FD_MAX_LEN + 1]; - char tunnel_id_str[FD_MAX_LEN + 1]; - char session_id_str[FD_MAX_LEN + 1]; - - snprintf(tunnel_fd_str, FD_MAX_LEN + 1, "%d", tunnel_fd); - snprintf(session_fd_str, FD_MAX_LEN + 1, "%d", session_fd); - snprintf(tunnel_id_str, FD_MAX_LEN + 1, "%d", tunnel_id); - snprintf(session_id_str, FD_MAX_LEN + 1, "%d", session_id); - - const char *l2tp_args[] = { - "pppd", - "nodetach", - "plugin", - "pppol2tp-android.so", - "session_fd", - session_fd_str, - "tunnel_fd", - tunnel_fd_str, - "session_id", - session_id_str, - "tunnel_id", - tunnel_id_str, - }; - const size_t args_len = ARRAY_SIZE(l2tp_args) + pppd_argc + 1; - char *args[args_len]; - - /* Populate args[] from l2tp_args[] and pppd_argv[] */ - memcpy(args, l2tp_args, sizeof(l2tp_args)); - memcpy(args + ARRAY_SIZE(l2tp_args), pppd_argv, - sizeof(char *) * pppd_argc); - args[args_len - 1] = NULL; - - execvp("pppd", args); - log_print(FATAL, "Exec() %s", strerror(errno)); - exit(SYSTEM_ERROR); /* Pretending a fatal error in pppd. */ - } - - log_print(INFO, "Pppd started (pid = %d)", pppd_pid); - -ret: - close(session_fd); - close(tunnel_fd); -} - -/** - * Start pppd daemon with pppopptp-android plugin. - * - * @param pptp_fd PPTP socket file descriptor - */ -void start_pppd_pptp(int pptp_fd) -{ - if (pppd_pid) { - log_print(WARNING, "Pppd is already started (pid = %d)", pppd_pid); - goto ret; - } - - log_print(INFO, "Starting pppd (pptp_fd = %d)", pptp_fd); - - pppd_pid = fork(); - if (pppd_pid < 0) { - log_print(FATAL, "Fork() %s", strerror(errno)); - exit(SYSTEM_ERROR); - } - - if (!pppd_pid) { - char pptp_fd_str[FD_MAX_LEN + 1]; - - snprintf(pptp_fd_str, FD_MAX_LEN + 1, "%d", pptp_fd); - - const char *pptp_args[] = { - "pppd", - "nodetach", - "plugin", - "pppopptp-android.so", - "pptp_socket", - pptp_fd_str, - }; - const size_t args_len = ARRAY_SIZE(pptp_args) + pppd_argc + 1; - char *args[args_len]; - - /* Populate args[] from pptp_args[] and pppd_argv[] */ - memcpy(args, pptp_args, sizeof(pptp_args)); - memcpy(args + ARRAY_SIZE(pptp_args), pppd_argv, - sizeof(char *) * pppd_argc); - args[args_len - 1] = NULL; - - execvp("pppd", args); - log_print(FATAL, "Exec() %s", strerror(errno)); - exit(SYSTEM_ERROR); /* Pretending a fatal error in pppd. */ - } - - log_print(INFO, "Pppd started (pid = %d)", pppd_pid); - -ret: - close(pptp_fd); -} diff --git a/mtpd.h b/mtpd.h deleted file mode 100644 index 290a583..0000000 --- a/mtpd.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -#ifndef __MTPD_H__ -#define __MTPD_H__ - -#if !defined(PX_PROTO_OLAC) -#define USING_UAPI -#endif - -#if defined(USING_UAPI) -/* This stuff isn't in uapi. */ -#define PX_PROTO_OLAC 3 -#define PX_PROTO_OPNS 4 - -struct sockaddr_pppopns { - sa_family_t sa_family; - unsigned int sa_protocol; - int tcp_socket; - uint16_t local; - uint16_t remote; -} __attribute__((packed)); - -struct sockaddr_pppolac { - sa_family_t sa_family; - unsigned int sa_protocol; - int udp_socket; - struct __attribute__((packed)) { - uint16_t tunnel; - uint16_t session; - } local, remote; -} __attribute__((packed)); -#endif - -/* The socket to the server. */ -extern int the_socket; - -enum exit_code { - SYSTEM_ERROR = 1, - NETWORK_ERROR = 2, - PROTOCOL_ERROR = 3, - CHALLENGE_FAILED = 4, - USER_REQUESTED = 5, - REMOTE_REQUESTED = 6, - PPPD_EXITED = 32, -}; - -enum log_level { - DEBUG = 0, - INFO = 1, - WARNING = 2, - ERROR = 3, - FATAL = 4, - LOG_MAX = 4, -}; - -void log_print(int level, char *format, ...); -void create_socket(int family, int type, char *server, char *port); -void start_pppd(int pppox); -void start_pppd_ol2tp(int tunnel_fd, int session_fd, int tunnel_id, - int session_id); -void start_pppd_pptp(int pptp_fd); - -/* Each protocol must implement everything defined in this structure. Note that - * timeout intervals are in milliseconds, where zero means forever. To indicate - * an error, one should use a negative exit code such as -REMOTE_REQUESTED. */ -struct protocol { - /* The name of this protocol. */ - char *name; - /* The number of arguments. */ - int arguments; - /* The usage of the arguments. */ - char *usage; - /* Connect to the server and return the next timeout interval. */ - int (*connect)(char **arguments); - /* Process the incoming packet and return the next timeout interval. */ - int (*process)(); - /* Handle the timeout event and return the next timeout interval. */ - int (*timeout)(); - /* Handle the shutdown event. */ - void (*shutdown)(); -}; - -#endif /* __MTPD_H__ */ diff --git a/mtpd.rc b/mtpd.rc deleted file mode 100644 index af701d5..0000000 --- a/mtpd.rc +++ /dev/null @@ -1,8 +0,0 @@ -service mtpd /system/bin/mtpd - class main - socket mtpd stream 600 system system - user vpn - group vpn inet - capabilities NET_ADMIN NET_RAW - disabled - oneshot diff --git a/pptp.c b/pptp.c deleted file mode 100644 index 7a58a27..0000000 --- a/pptp.c +++ /dev/null @@ -1,583 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -/* A simple implementation of PPTP Network Server (RFC 2637) which only - * creates a single session. The following code only handles control packets. - * Data packets are handled by PPPoPNS driver which can be found in Android - * kernel tree. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mtpd.h" - -enum pptp_message { - SCCRQ = 1, - SCCRP = 2, - STOPCCRQ = 3, - STOPCCRP = 4, - ECHORQ = 5, - ECHORP = 6, - OCRQ = 7, - OCRP = 8, - ICRQ = 9, - ICRP = 10, - ICCN = 11, - CCRQ = 12, - CDN = 13, - WEN = 14, - SLI = 15, - MESSAGE_MAX = 15, -}; - -static char *messages[] = { - NULL, "SCCRQ", "SCCRP", "STOPCCRQ", "STOPCCRP", "ECHORQ", "ECHORP", - "OCRQ", "OCRP", "ICRQ", "ICRP", "ICCN", "CCRQ", "CDN", "WEN", "SLI", -}; - -static uint8_t lengths[] = { - 0, 156, 156, 16, 16, 16, 20, 168, 32, 220, 24, 28, 16, 148, 40, 24, -}; - -#define CONTROL_MESSAGE htons(1) -#define MAGIC_COOKIE htonl(0x1A2B3C4D) -#define PROTOCOL_VERSION htons(0x0100) - -#define RESULT_OK 1 -#define RESULT_ERROR 2 - -/* Some implementation uses 0 instead of 1, so we allow both of them. */ -#define ESTABLISHED(result) (result <= 1) - -#define HEADER_SIZE 8 -#define MIN_MESSAGE_SIZE 10 - -static __be16 local; -static __be16 remote; -static uint16_t state; -static const char *remote_name; /* server host name or IP address */ - -#define MAX_PACKET_LENGTH 220 - -/* We define all the fields we used in this structure. Type conversion and byte - * alignment are solved in one place. Although it looks a little bit ugly, it - * really makes life easier. */ -static struct packet { - int length; - int expect; - union { - uint8_t buffer[MAX_PACKET_LENGTH]; - struct { - struct __attribute__((packed)) { - uint16_t length; - uint16_t type; - uint32_t cookie; - } header; - uint16_t message; - uint16_t reserved; - union { - struct __attribute__((packed)) { - uint16_t protocol_version; - uint8_t result; - uint8_t error; - uint32_t framing; - uint32_t bearer; - uint16_t channels; - uint16_t firmware_revision; - char host[64]; - } sccrp, sccrq; - struct __attribute__((packed)) { - uint16_t call; - uint16_t serial; - uint32_t minimum_speed; - uint32_t maximum_speed; - uint32_t bearer; - uint32_t framing; - uint16_t window_size; - } ocrq; - struct __attribute__((packed)) { - uint16_t call; - uint16_t peer; - uint8_t result; - } ocrp, icrp; - struct __attribute__((packed)) { - uint32_t identifier; - uint8_t result; - } echorq, echorp; - struct __attribute__((packed)) { - uint16_t call; - } icrq, ccrq, cdn; - }; - } __attribute__((packed)); - } __attribute__((aligned(4))); -} incoming, outgoing; - -static void set_message(uint16_t message) -{ - uint16_t length = lengths[message]; - memset(outgoing.buffer, 0, length); - outgoing.length = length; - outgoing.header.length = htons(length); - outgoing.header.type = CONTROL_MESSAGE; - outgoing.header.cookie = MAGIC_COOKIE; - outgoing.message = htons(message); -} - -static void send_packet() -{ - send(the_socket, outgoing.buffer, outgoing.length, 0); -} - -static int recv_packet() -{ - int length; - - /* We are going to read a new message if incoming.expect is 0. */ - if (!incoming.expect) { - incoming.length = 0; - incoming.expect = HEADER_SIZE; - } - - /* The longest message defined in RFC 2637 is 220 bytes, but the protocol - * itself allows up to 65536 bytes. Therefore we always read a complete - * message but only keep the first 220 bytes before passing up. */ - length = incoming.expect - incoming.length; - if (incoming.length >= MAX_PACKET_LENGTH) { - uint8_t buffer[length]; - length = recv(the_socket, buffer, length, 0); - } else { - if (incoming.expect > MAX_PACKET_LENGTH) { - length = MAX_PACKET_LENGTH - incoming.length; - } - length = recv(the_socket, &incoming.buffer[incoming.length], length, 0); - } - if (length == -1) { - if (errno == EINTR) { - return 0; - } - log_print(FATAL, "Recv() %s", strerror(errno)); - exit(NETWORK_ERROR); - } - if (length == 0) { - log_print(DEBUG, "Connection closed"); - log_print(INFO, "Remote server hung up"); - return -REMOTE_REQUESTED; - } - incoming.length += length; - - /* If incoming.header is valid, check cookie and update incoming.expect. */ - if (incoming.length == HEADER_SIZE && incoming.expect == HEADER_SIZE) { - if (incoming.header.cookie != MAGIC_COOKIE) { - log_print(DEBUG, "Loss of synchronization"); - log_print(ERROR, "Protocol error"); - return -PROTOCOL_ERROR; - } - incoming.expect = ntohs(incoming.header.length); - if (incoming.expect < HEADER_SIZE) { - log_print(DEBUG, "Invalid message length"); - log_print(ERROR, "Protocol error"); - return -PROTOCOL_ERROR; - } - } - - /* Now we have a complete message. Reset incoming.expect. */ - if (incoming.length == incoming.expect) { - incoming.expect = 0; - - /* Return 1 if it is a control message. */ - if (incoming.header.type == CONTROL_MESSAGE) { - return 1; - } - log_print(DEBUG, "Ignored non-control message (type = %u)", - (unsigned)ntohs(incoming.header.type)); - } - return 0; -} - -static int pptp_connect(char **arguments) -{ - remote_name = arguments[0]; - - create_socket(AF_UNSPEC, SOCK_STREAM, arguments[0], arguments[1]); - - log_print(DEBUG, "Sending SCCRQ"); - state = SCCRQ; - set_message(SCCRQ); - outgoing.sccrq.protocol_version = PROTOCOL_VERSION; - outgoing.sccrq.framing = htonl(3); - outgoing.sccrq.bearer = htonl(3); - outgoing.sccrq.channels = htons(1); - strcpy(outgoing.sccrq.host, "anonymous"); - send_packet(); - return 0; -} - -/** - * Check if upstream kernel implementation of PPTP should be used. - * - * @return true If upstream PPTP should be used, which is the case if - * the obsolete OPNS feature is not available. - */ -static bool check_pptp(void) -{ - int fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OPNS); - - if (fd < 0) { - return true; - } else { - close(fd); - return false; - } -} - -/** - * Create OPNS session. - * - * @deprecated It will be removed soon in favor of upstream PPTP. - * - * @return PPPoX socket file descriptor - */ -static int create_pppox_opns(void) -{ - int pppox; - - log_print(WARNING, "Using deprecated OPNS protocol. " - "Its support will be removed soon. " - "Please enable PPTP support in your kernel"); - - log_print(INFO, "Creating PPPoX socket"); - pppox = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OPNS); - - if (pppox == -1) { - log_print(FATAL, "Socket() %s", strerror(errno)); - exit(SYSTEM_ERROR); - } else { - struct sockaddr_pppopns address = { - .sa_family = AF_PPPOX, - .sa_protocol = PX_PROTO_OPNS, - .tcp_socket = the_socket, - .local = local, - .remote = remote, - }; - if (connect(pppox, (struct sockaddr *)&address, sizeof(address))) { - log_print(FATAL, "Connect() %s", strerror(errno)); - exit(SYSTEM_ERROR); - } - } - return pppox; -} - -/** - * Get IP address by host name. - * - * @param name Host name to get IP address for - * - * @return IP address for given host name - */ -static struct in_addr get_addr_by_name(const char *name) -{ - struct addrinfo hints; - struct addrinfo *res, *rp; - struct in_addr addr; - int err; - - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_INET; /* allow only IPv4 */ - hints.ai_socktype = SOCK_DGRAM; /* UDP */ - hints.ai_protocol = 0; /* any protocol */ - - err = getaddrinfo(name, NULL, &hints, &res); - if (err) { - log_print(FATAL, "%s: getaddrinfo: %s", __func__, gai_strerror(err)); - exit(SYSTEM_ERROR); - } - - for (rp = res; rp != NULL; rp = rp->ai_next) { - /* For now we only support IPv4 */ - if (rp->ai_family == AF_INET) { - addr = ((struct sockaddr_in *)rp->ai_addr)->sin_addr; - break; - } - } - - if (rp == NULL) { - log_print(FATAL, "%s: No IPv4 addresses found", __func__); - freeaddrinfo(res); - exit(SYSTEM_ERROR); - } - - freeaddrinfo(res); - - return addr; -} - -/** - * Get local IP address. - * - * Make a socket connection with remote server and then call getsockname() on - * the connected socket. This will return the local IP address. - * - * @param remote_addr Server IP address - * - * @return Local IP address - */ -static struct in_addr get_local_addr(struct in_addr remote_addr) -{ - int sock; - struct sockaddr_in addr; - socklen_t addr_len; - - addr_len = sizeof(struct sockaddr_in); - addr.sin_addr = remote_addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(0); - - sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) { - log_print(FATAL, "%s: Socket() %s", __func__, strerror(errno)); - exit(SYSTEM_ERROR); - } - - if (connect(sock, (struct sockaddr*)&addr, sizeof(addr))) { - close(sock); - log_print(FATAL, "%s: Connect() %s", __func__, strerror(errno)); - exit(SYSTEM_ERROR); - } - - getsockname(sock, (struct sockaddr*)&addr, &addr_len); - close(sock); - - return addr.sin_addr; -} - -/** - * Create PPTP session. - * - * @return PPTP socket file descriptor - */ -static int create_pppox_pptp(void) -{ - int pptp_fd; - struct sockaddr_pppox src, dst; - struct in_addr remote_addr; /* server IP address */ - struct in_addr local_addr; /* client IP address */ - - remote_addr = get_addr_by_name(remote_name); - local_addr = get_local_addr(remote_addr); - - src.sa_family = AF_PPPOX; - src.sa_protocol = PX_PROTO_PPTP; - src.sa_addr.pptp.call_id = ntohs(local); - src.sa_addr.pptp.sin_addr = local_addr; - - dst.sa_family = AF_PPPOX; - dst.sa_protocol = PX_PROTO_PPTP; - dst.sa_addr.pptp.call_id = ntohs(remote); - dst.sa_addr.pptp.sin_addr = remote_addr; - - pptp_fd = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_PPTP); - if (pptp_fd < 0) { - log_print(FATAL, "Failed to create PPTP socket (%s)", strerror(errno)); - exit(SYSTEM_ERROR); - } - - if (bind(pptp_fd, (struct sockaddr*)&src, sizeof(src))) { - log_print(FATAL, "Failed to bind PPTP socket (%s)", strerror(errno)); - close(pptp_fd); - exit(SYSTEM_ERROR); - } - - if (connect(pptp_fd, (struct sockaddr*)&dst, sizeof(dst))) { - log_print(FATAL, "Failed to connect PPTP socket (%s)", strerror(errno)); - close(pptp_fd); - exit(SYSTEM_ERROR); - } - - return pptp_fd; -} - -static int pptp_process() -{ - int result = recv_packet(); - if (result <= 0) { - return result; - } - - if (incoming.length < MIN_MESSAGE_SIZE) { - log_print(DEBUG, "Control message too short"); - return 0; - } - incoming.message = ntohs(incoming.message); - if (incoming.message > MESSAGE_MAX || !messages[incoming.message]) { - log_print(DEBUG, "Received UNKNOWN %d", incoming.message); - return 0; - } - if (incoming.length < lengths[incoming.message]) { - log_print(DEBUG, "Received %s with invalid length (length = %d)", - messages[incoming.message], incoming.length); - return 0; - } - - switch(incoming.message) { - case SCCRP: - if (state == SCCRQ) { - if (incoming.sccrp.protocol_version == PROTOCOL_VERSION && - ESTABLISHED(incoming.sccrp.result)) { - while (!local) { - local = random(); - } - log_print(DEBUG, "Received SCCRP -> Sending OCRQ " - "(local = %u)", (unsigned)ntohs(local)); - log_print(INFO, "Tunnel established"); - state = OCRQ; - set_message(OCRQ); - outgoing.ocrq.call = local; - outgoing.ocrq.serial = random(); - outgoing.ocrq.minimum_speed = htonl(1000); - outgoing.ocrq.maximum_speed = htonl(100000000); - outgoing.ocrq.bearer = htonl(3); - outgoing.ocrq.framing = htonl(3); - outgoing.ocrq.window_size = htons(8192); - send_packet(); - return 0; - } - log_print(DEBUG, "Received SCCRP (result = %d)", - incoming.sccrq.result); - log_print(INFO, "Remote server hung up"); - return -REMOTE_REQUESTED; - } - break; - - case OCRP: - if (state == OCRQ && incoming.ocrp.peer == local) { - if (ESTABLISHED(incoming.ocrp.result)) { - remote = incoming.ocrp.call; - log_print(DEBUG, "Received OCRQ (remote = %u)", - (unsigned)ntohs(remote)); - log_print(INFO, "Session established"); - state = OCRP; - - if (check_pptp()) - start_pppd_pptp(create_pppox_pptp()); - else - start_pppd(create_pppox_opns()); - - return 0; - } - log_print(DEBUG, "Received OCRP (result = %d)", - incoming.ocrp.result); - log_print(INFO, "Remote server hung up"); - return -REMOTE_REQUESTED; - } - break; - - case STOPCCRQ: - log_print(DEBUG, "Received STOPCCRQ"); - log_print(INFO, "Remote server hung up"); - state = STOPCCRQ; - return -REMOTE_REQUESTED; - - case CCRQ: - /* According to RFC 2637 page 45, we should never receive CCRQ for - * outgoing calls. However, some implementation only acts as PNS and - * always uses CCRQ to clear a call, so here we still handle it. */ - if (state == OCRP && incoming.ccrq.call == remote) { - log_print(DEBUG, "Received CCRQ (remote = %u)", - (unsigned)ntohs(remote)); - log_print(INFO, "Remote server hung up"); - return -REMOTE_REQUESTED; - } - break; - - case CDN: - if (state == OCRP && incoming.cdn.call == remote) { - log_print(DEBUG, "Received CDN (remote = %u)", - (unsigned)ntohs(remote)); - log_print(INFO, "Remote server hung up"); - return -REMOTE_REQUESTED; - } - break; - - case ECHORQ: - log_print(DEBUG, "Received ECHORQ -> Sending ECHORP"); - set_message(ECHORP); - outgoing.echorp.identifier = incoming.echorq.identifier; - outgoing.echorp.result = RESULT_OK; - send_packet(); - return 0; - - case WEN: - case SLI: - log_print(DEBUG, "Recevied %s", messages[incoming.message]); - return 0; - - case ICRQ: - log_print(DEBUG, "Received ICRQ (remote = %u, call = %u) -> " - "Sending ICRP with error", (unsigned)ntohs(remote), - (unsigned)ntohs(incoming.icrq.call)); - set_message(ICRP); - outgoing.icrp.peer = incoming.icrq.call; - outgoing.icrp.result = RESULT_ERROR; - send_packet(); - return 0; - - case OCRQ: - log_print(DEBUG, "Received OCRQ (remote = %u, call = %u) -> " - "Sending OCRP with error", (unsigned)ntohs(remote), - (unsigned)ntohs(incoming.ocrq.call)); - set_message(OCRP); - outgoing.ocrp.peer = incoming.ocrq.call; - outgoing.ocrp.result = RESULT_ERROR; - send_packet(); - return 0; - } - - /* We reach here if we got an unexpected message. Just log it. */ - log_print(DEBUG, "Received UNEXPECTED %s", messages[incoming.message]); - return 0; -} - -static int pptp_timeout() -{ - return 0; -} - -static void pptp_shutdown() -{ - /* Normally we should send STOPCCRQ and wait for STOPCCRP, but this might - * block for a long time. Here we simply take the shortcut: do nothing. */ -} - -struct protocol pptp = { - .name = "pptp", - .arguments = 2, - .usage = " ", - .connect = pptp_connect, - .process = pptp_process, - .timeout = pptp_timeout, - .shutdown = pptp_shutdown, -}; -- cgit v1.2.3