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