/* * 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 <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <linux/if_pppopns.h> #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 uint16_t local; static uint16_t remote; static uint16_t state; #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 = %d)", ntohs(incoming.header.type)); } return 0; } static int pptp_connect(int argc, char **argv) { if (argc < 2) { return -USAGE_ERROR; } create_socket(AF_UNSPEC, SOCK_STREAM, argv[0], argv[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; } static int create_pppox() { int pppox; 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)) != 0) { log_print(FATAL, "Connect() %s", strerror(errno)); exit(SYSTEM_ERROR); } } return pppox; } 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 = %d)", 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 = %d)", remote); log_print(INFO, "Session established"); state = OCRP; start_pppd(create_pppox()); 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 = %d)", 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 = %d)", 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 = %d) -> Sending ICRP " "with error", 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 = %d) -> Sending OCRP " "with error", 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", .usage = "<server> <port>", .connect = pptp_connect, .process = pptp_process, .timeout = pptp_timeout, .shutdown = pptp_shutdown, };