1063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh/* 2063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * Copyright (C) 2009 The Android Open Source Project 3063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * 4063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License"); 5063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * you may not use this file except in compliance with the License. 6063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * You may obtain a copy of the License at 7063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * 8063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * http://www.apache.org/licenses/LICENSE-2.0 9063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * 10063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * Unless required by applicable law or agreed to in writing, software 11063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS, 12063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * See the License for the specific language governing permissions and 14063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * limitations under the License. 15063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh */ 16063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 17063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh/* A simple implementation of PPTP Network Server (RFC 2637) which only 18063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * creates a single session. The following code only handles control packets. 19063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * Data packets are handled by PPPoPNS driver which can be found in Android 20063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * kernel tree. */ 21063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 22063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh#include <stdio.h> 23063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh#include <stdlib.h> 24063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh#include <string.h> 25063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh#include <errno.h> 26063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh#include <sys/types.h> 27063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh#include <sys/socket.h> 28063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh#include <arpa/inet.h> 290f725857a9901b62b20c96b2ee70372660d13f46Chia-chi Yeh#include <linux/netdevice.h> 300f725857a9901b62b20c96b2ee70372660d13f46Chia-chi Yeh#include <linux/if_pppox.h> 31063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 32063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh#include "mtpd.h" 33063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 34063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yehenum pptp_message { 35063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh SCCRQ = 1, 36063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh SCCRP = 2, 37063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh STOPCCRQ = 3, 38063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh STOPCCRP = 4, 39063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh ECHORQ = 5, 40063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh ECHORP = 6, 41063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh OCRQ = 7, 42063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh OCRP = 8, 43063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh ICRQ = 9, 44063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh ICRP = 10, 45063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh ICCN = 11, 46063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh CCRQ = 12, 47063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh CDN = 13, 48063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh WEN = 14, 49063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh SLI = 15, 50063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh MESSAGE_MAX = 15, 51063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh}; 52063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 53063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yehstatic char *messages[] = { 54063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh NULL, "SCCRQ", "SCCRP", "STOPCCRQ", "STOPCCRP", "ECHORQ", "ECHORP", 55063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh "OCRQ", "OCRP", "ICRQ", "ICRP", "ICCN", "CCRQ", "CDN", "WEN", "SLI", 56063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh}; 57063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 58063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yehstatic uint8_t lengths[] = { 59063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 0, 156, 156, 16, 16, 16, 20, 168, 32, 220, 24, 28, 16, 148, 40, 24, 60063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh}; 61063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 62063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh#define CONTROL_MESSAGE htons(1) 63063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh#define MAGIC_COOKIE htonl(0x1A2B3C4D) 64063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh#define PROTOCOL_VERSION htons(0x0100) 65063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 66063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh#define RESULT_OK 1 67063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh#define RESULT_ERROR 2 68063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 69063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh/* Some implementation uses 0 instead of 1, so we allow both of them. */ 70063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh#define ESTABLISHED(result) (result <= 1) 71063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 72063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh#define HEADER_SIZE 8 73063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh#define MIN_MESSAGE_SIZE 10 74063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 75063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yehstatic uint16_t local; 76063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yehstatic uint16_t remote; 77063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yehstatic uint16_t state; 78063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 79063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh#define MAX_PACKET_LENGTH 220 80063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 81063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh/* We define all the fields we used in this structure. Type conversion and byte 82063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * alignment are solved in one place. Although it looks a little bit ugly, it 83063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * really makes life easier. */ 84063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yehstatic struct packet { 85063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh int length; 86063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh int expect; 87063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh union { 88063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint8_t buffer[MAX_PACKET_LENGTH]; 89063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh struct { 90063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh struct __attribute__((packed)) { 91063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint16_t length; 92063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint16_t type; 93063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint32_t cookie; 94063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } header; 95063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint16_t message; 96063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint16_t reserved; 97063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh union { 98063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh struct __attribute__((packed)) { 99063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint16_t protocol_version; 100063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint8_t result; 101063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint8_t error; 102063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint32_t framing; 103063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint32_t bearer; 104063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint16_t channels; 105063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint16_t firmware_revision; 106063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh char host[64]; 107063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } sccrp, sccrq; 108063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh struct __attribute__((packed)) { 109063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint16_t call; 110063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint16_t serial; 111063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint32_t minimum_speed; 112063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint32_t maximum_speed; 113063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint32_t bearer; 114063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint32_t framing; 115063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint16_t window_size; 116063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } ocrq; 117063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh struct __attribute__((packed)) { 118063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint16_t call; 119063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint16_t peer; 120063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint8_t result; 121063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } ocrp, icrp; 122063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh struct __attribute__((packed)) { 123063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint32_t identifier; 124063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint8_t result; 125063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } echorq, echorp; 126063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh struct __attribute__((packed)) { 127063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint16_t call; 128063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } icrq, ccrq, cdn; 129063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh }; 130063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } __attribute__((packed)); 131063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } __attribute__((aligned(4))); 132063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh} incoming, outgoing; 133063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 134063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yehstatic void set_message(uint16_t message) 135063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh{ 136063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint16_t length = lengths[message]; 137063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh memset(outgoing.buffer, 0, length); 138063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.length = length; 139063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.header.length = htons(length); 140063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.header.type = CONTROL_MESSAGE; 141063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.header.cookie = MAGIC_COOKIE; 142063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.message = htons(message); 143063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh} 144063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 145063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yehstatic void send_packet() 146063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh{ 147063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh send(the_socket, outgoing.buffer, outgoing.length, 0); 148063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh} 149063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 150063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yehstatic int recv_packet() 151063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh{ 152063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh int length; 153063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 154063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh /* We are going to read a new message if incoming.expect is 0. */ 155063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (!incoming.expect) { 156063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh incoming.length = 0; 157063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh incoming.expect = HEADER_SIZE; 158063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 159063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 160063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh /* The longest message defined in RFC 2637 is 220 bytes, but the protocol 161063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * itself allows up to 65536 bytes. Therefore we always read a complete 162063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * message but only keep the first 220 bytes before passing up. */ 163063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh length = incoming.expect - incoming.length; 164063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (incoming.length >= MAX_PACKET_LENGTH) { 165063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh uint8_t buffer[length]; 166063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh length = recv(the_socket, buffer, length, 0); 167063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } else { 168063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (incoming.expect > MAX_PACKET_LENGTH) { 169063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh length = MAX_PACKET_LENGTH - incoming.length; 170063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 171063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh length = recv(the_socket, &incoming.buffer[incoming.length], length, 0); 172063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 173063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (length == -1) { 174063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (errno == EINTR) { 175063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return 0; 176063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 177063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(FATAL, "Recv() %s", strerror(errno)); 178063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh exit(NETWORK_ERROR); 179063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 180063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (length == 0) { 181063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Connection closed"); 182063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(INFO, "Remote server hung up"); 183063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return -REMOTE_REQUESTED; 184063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 185063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh incoming.length += length; 186063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 187063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh /* If incoming.header is valid, check cookie and update incoming.expect. */ 188063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (incoming.length == HEADER_SIZE && incoming.expect == HEADER_SIZE) { 189063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (incoming.header.cookie != MAGIC_COOKIE) { 190063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Loss of synchronization"); 191063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(ERROR, "Protocol error"); 192063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return -PROTOCOL_ERROR; 193063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 194063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh incoming.expect = ntohs(incoming.header.length); 195063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (incoming.expect < HEADER_SIZE) { 196063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Invalid message length"); 197063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(ERROR, "Protocol error"); 198063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return -PROTOCOL_ERROR; 199063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 200063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 201063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 202063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh /* Now we have a complete message. Reset incoming.expect. */ 203063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (incoming.length == incoming.expect) { 204063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh incoming.expect = 0; 205063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 206063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh /* Return 1 if it is a control message. */ 207063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (incoming.header.type == CONTROL_MESSAGE) { 208063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return 1; 209063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 210063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Ignored non-control message (type = %d)", 211ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh ntohs(incoming.header.type)); 212063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 213063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return 0; 214063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh} 215063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 2167b66d20359dd1c5586ecb1594d3ee929c5b42624Chia-chi Yehstatic int pptp_connect(char **arguments) 217063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh{ 2187b66d20359dd1c5586ecb1594d3ee929c5b42624Chia-chi Yeh create_socket(AF_UNSPEC, SOCK_STREAM, arguments[0], arguments[1]); 219063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 220063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Sending SCCRQ"); 221063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh state = SCCRQ; 222063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh set_message(SCCRQ); 223063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.sccrq.protocol_version = PROTOCOL_VERSION; 224063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.sccrq.framing = htonl(3); 225063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.sccrq.bearer = htonl(3); 226063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.sccrq.channels = htons(1); 227063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh strcpy(outgoing.sccrq.host, "anonymous"); 228063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh send_packet(); 229063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return 0; 230063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh} 231063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 2320f725857a9901b62b20c96b2ee70372660d13f46Chia-chi Yehstatic int create_pppox() 233063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh{ 2340f725857a9901b62b20c96b2ee70372660d13f46Chia-chi Yeh int pppox = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OPNS); 235063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(INFO, "Creating PPPoX socket"); 236063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 237063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (pppox == -1) { 238063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(FATAL, "Socket() %s", strerror(errno)); 2390f725857a9901b62b20c96b2ee70372660d13f46Chia-chi Yeh exit(SYSTEM_ERROR); 240063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } else { 241063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh struct sockaddr_pppopns address = { 242063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh .sa_family = AF_PPPOX, 2430f725857a9901b62b20c96b2ee70372660d13f46Chia-chi Yeh .sa_protocol = PX_PROTO_OPNS, 244063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh .tcp_socket = the_socket, 245063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh .local = local, 246063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh .remote = remote, 247063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh }; 248ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh if (connect(pppox, (struct sockaddr *)&address, sizeof(address))) { 249063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(FATAL, "Connect() %s", strerror(errno)); 2500f725857a9901b62b20c96b2ee70372660d13f46Chia-chi Yeh exit(SYSTEM_ERROR); 251063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 252063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 253063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return pppox; 254063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh} 255063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 256063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yehstatic int pptp_process() 257063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh{ 258063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh int result = recv_packet(); 259063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (result <= 0) { 260063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return result; 261063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 262063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 263063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (incoming.length < MIN_MESSAGE_SIZE) { 264063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Control message too short"); 265063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return 0; 266063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 267063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh incoming.message = ntohs(incoming.message); 268063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (incoming.message > MESSAGE_MAX || !messages[incoming.message]) { 269063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Received UNKNOWN %d", incoming.message); 270063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return 0; 271063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 272063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (incoming.length < lengths[incoming.message]) { 273063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Received %s with invalid length (length = %d)", 274ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh messages[incoming.message], incoming.length); 275063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return 0; 276063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 277063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 278063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh switch(incoming.message) { 279063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh case SCCRP: 280063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (state == SCCRQ) { 281ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh if (incoming.sccrp.protocol_version == PROTOCOL_VERSION && 282ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh ESTABLISHED(incoming.sccrp.result)) { 283063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh while (!local) { 284063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh local = random(); 285063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 286063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Received SCCRP -> Sending OCRQ " 287ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh "(local = %d)", local); 288063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(INFO, "Tunnel established"); 289063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh state = OCRQ; 290063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh set_message(OCRQ); 291063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.ocrq.call = local; 292063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.ocrq.serial = random(); 293063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.ocrq.minimum_speed = htonl(1000); 294063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.ocrq.maximum_speed = htonl(100000000); 295063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.ocrq.bearer = htonl(3); 296063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.ocrq.framing = htonl(3); 297063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.ocrq.window_size = htons(8192); 298063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh send_packet(); 299063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return 0; 300063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 301063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Received SCCRP (result = %d)", 302ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh incoming.sccrq.result); 303063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(INFO, "Remote server hung up"); 304063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return -REMOTE_REQUESTED; 305063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 306063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh break; 307063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 308063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh case OCRP: 309063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (state == OCRQ && incoming.ocrp.peer == local) { 310063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (ESTABLISHED(incoming.ocrp.result)) { 311063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh remote = incoming.ocrp.call; 312063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Received OCRQ (remote = %d)", remote); 313063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(INFO, "Session established"); 314063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh state = OCRP; 315063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh start_pppd(create_pppox()); 316063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return 0; 317063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 318063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Received OCRP (result = %d)", 319ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh incoming.ocrp.result); 320063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(INFO, "Remote server hung up"); 321063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return -REMOTE_REQUESTED; 322063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 323063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh break; 324063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 325063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh case STOPCCRQ: 326063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Received STOPCCRQ"); 327063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(INFO, "Remote server hung up"); 328063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh state = STOPCCRQ; 329063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return -REMOTE_REQUESTED; 330063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 331063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh case CCRQ: 332063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh /* According to RFC 2637 page 45, we should never receive CCRQ for 333063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * outgoing calls. However, some implementation only acts as PNS and 334063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * always uses CCRQ to clear a call, so here we still handle it. */ 335063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (state == OCRP && incoming.ccrq.call == remote) { 336063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Received CCRQ (remote = %d)", remote); 337063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(INFO, "Remote server hung up"); 338063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return -REMOTE_REQUESTED; 339063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 340063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh break; 341063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 342063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh case CDN: 343063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh if (state == OCRP && incoming.cdn.call == remote) { 344063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Received CDN (remote = %d)", remote); 345063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(INFO, "Remote server hung up"); 346063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return -REMOTE_REQUESTED; 347063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 348063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh break; 349063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 350063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh case ECHORQ: 351063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Received ECHORQ -> Sending ECHORP"); 352063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh set_message(ECHORP); 353063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.echorp.identifier = incoming.echorq.identifier; 354063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.echorp.result = RESULT_OK; 355063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh send_packet(); 356063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return 0; 357063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 358063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh case WEN: 359063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh case SLI: 360063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Recevied %s", messages[incoming.message]); 361063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return 0; 362063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 363063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh case ICRQ: 364063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Received ICRQ (remote = %d) -> Sending ICRP " 365ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh "with error", incoming.icrq.call); 366063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh set_message(ICRP); 367063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.icrp.peer = incoming.icrq.call; 368063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.icrp.result = RESULT_ERROR; 369063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh send_packet(); 370063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return 0; 371063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 372063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh case OCRQ: 373063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Received OCRQ (remote = %d) -> Sending OCRP " 374ea299e6828421f15b1d23256527f2cd3668b9915Chia-chi Yeh "with error", incoming.ocrq.call); 375063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh set_message(OCRP); 376063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.ocrp.peer = incoming.ocrq.call; 377063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh outgoing.ocrp.result = RESULT_ERROR; 378063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh send_packet(); 379063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return 0; 380063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh } 381063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 382063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh /* We reach here if we got an unexpected message. Just log it. */ 383063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh log_print(DEBUG, "Received UNEXPECTED %s", messages[incoming.message]); 384063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return 0; 385063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh} 386063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 387063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yehstatic int pptp_timeout() 388063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh{ 389063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh return 0; 390063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh} 391063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 392063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yehstatic void pptp_shutdown() 393063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh{ 394063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh /* Normally we should send STOPCCRQ and wait for STOPCCRP, but this might 395063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh * block for a long time. Here we simply take the shortcut: do nothing. */ 396063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh} 397063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh 398063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yehstruct protocol pptp = { 399063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh .name = "pptp", 4007b66d20359dd1c5586ecb1594d3ee929c5b42624Chia-chi Yeh .arguments = 2, 401063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh .usage = "<server> <port>", 402063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh .connect = pptp_connect, 403063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh .process = pptp_process, 404063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh .timeout = pptp_timeout, 405063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh .shutdown = pptp_shutdown, 406063bb92976a72c53044c1c147fb4d1feec9716eeChia-chi Yeh}; 407