pptp.c 19.7 KB
Newer Older
1 2 3 4 5 6
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
K
Kozlov Dmitry 已提交
7
#include <fcntl.h>
K
Kozlov Dmitry 已提交
8
#include <time.h>
9 10
#include <arpa/inet.h>
#include <netinet/in.h>
K
Kozlov Dmitry 已提交
11
#include <sys/socket.h>
12 13 14

#include "if_pppox.h"

15
#include "events.h"
16 17
#include "list.h"
#include "pptp_prot.h"
K
Kozlov Dmitry 已提交
18
#include "triton.h"
19 20
#include "log.h"
#include "ppp.h"
21
#include "mempool.h"
22
#include "iprange.h"
23
#include "utils.h"
24

D
Dmitry Kozlov 已提交
25 26
#include "memdebug.h"

27 28
#define STATE_IDLE 0
#define STATE_ESTB 1
29
#define STATE_PPP  2
K
Kozlov Dmitry 已提交
30 31
#define STATE_FIN  3
#define STATE_CLOSE 4
32 33 34

struct pptp_conn_t
{
35
	struct triton_context_t ctx;
36
	struct triton_md_handler_t hnd;
D
Dmitry Kozlov 已提交
37 38
	struct triton_timer_t timeout_timer;
	struct triton_timer_t echo_timer;
K
Kozlov Dmitry 已提交
39 40
	int call_id;
	int peer_call_id;
41
	int state;
42
	int echo_sent;
43

D
Dmitry Kozlov 已提交
44
	uint8_t *in_buf;
45
	int in_size;
D
Dmitry Kozlov 已提交
46
	uint8_t *out_buf;
47 48 49
	int out_size;
	int out_pos;

K
Kozlov Dmitry 已提交
50
	struct ppp_ctrl_t ctrl;
51
	struct ppp_t ppp;
52 53
};

54 55
static int conf_timeout = 3;
static int conf_echo_interval = 0;
K
Kozlov Dmitry 已提交
56 57
static int conf_echo_failure = 3;
static int conf_verbose = 0;
58

59 60
static mempool_t conn_pool;

K
Kozlov Dmitry 已提交
61 62
static int pptp_read(struct triton_md_handler_t *h);
static int pptp_write(struct triton_md_handler_t *h);
63
static void pptp_timeout(struct triton_timer_t *);
64 65
static void ppp_started(struct ppp_t *);
static void ppp_finished(struct ppp_t *);
66 67 68

static void disconnect(struct pptp_conn_t *conn)
{
K
Kozlov Dmitry 已提交
69 70
	log_ppp_debug("pptp: disconnect\n");

71
	triton_md_unregister_handler(&conn->hnd);
K
Kozlov Dmitry 已提交
72
	close(conn->hnd.fd);
K
Kozlov Dmitry 已提交
73
	
74
	if (conn->timeout_timer.tpd)
75 76
		triton_timer_del(&conn->timeout_timer);

77
	if (conn->echo_timer.tpd)
78 79
		triton_timer_del(&conn->echo_timer);

K
Kozlov Dmitry 已提交
80 81 82 83
	if (conn->state == STATE_PPP) {
		conn->state = STATE_CLOSE;
		ppp_terminate(&conn->ppp, 1);
	}
84 85

	triton_event_fire(EV_CTRL_FINISHED, &conn->ppp);
K
Kozlov Dmitry 已提交
86
	
87
	triton_context_unregister(&conn->ctx);
D
Dmitry Kozlov 已提交
88 89 90

	if (conn->ppp.chan_name)
		_free(conn->ppp.chan_name);
K
Kozlov Dmitry 已提交
91
	
D
Dmitry Kozlov 已提交
92 93
	_free(conn->in_buf);
	_free(conn->out_buf);
94 95 96
	_free(conn->ctrl.calling_station_id);
	_free(conn->ctrl.called_station_id);
	mempool_free(conn);
97 98
}

K
Kozlov Dmitry 已提交
99
static int post_msg(struct pptp_conn_t *conn, void *buf, int size)
100 101
{
	int n;
K
Kozlov Dmitry 已提交
102
	if (conn->out_size) {
K
Kozlov Dmitry 已提交
103
		log_error("pptp: buffer is not empty\n");
104 105 106
		return -1;
	}

K
Kozlov Dmitry 已提交
107 108 109 110 111 112
	n=write(conn->hnd.fd, buf, size);
	if (n < 0) {
		if (errno == EINTR || errno == EAGAIN)
			n = 0;
		else {
			if (errno != EPIPE)
K
Kozlov Dmitry 已提交
113
			log_ppp_debug("pptp: write: %s\n", strerror(errno));
114 115 116 117
			return -1;
		}
	}

K
Kozlov Dmitry 已提交
118 119 120
	if ( n<size ) {
		memcpy(conn->out_buf, buf + n, size - n);
		triton_md_enable_handler(&conn->hnd, MD_MODE_WRITE);
121 122 123 124 125
	}

	return 0;
}

K
Kozlov Dmitry 已提交
126
static int send_pptp_stop_ctrl_conn_rqst(struct pptp_conn_t *conn, int reason)
127
{
K
Kozlov Dmitry 已提交
128 129 130
	struct pptp_stop_ctrl_conn msg = {
		.header = PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RQST),
		.reason_result = hton8(reason),
131 132
	};

K
Kozlov Dmitry 已提交
133 134 135
	if (conf_verbose)
		log_ppp_info("send [PPTP Stop-Ctrl-Conn-Request <Reason %i>]\n", reason);

K
Kozlov Dmitry 已提交
136
	return post_msg(conn, &msg, sizeof(msg));
137 138
}

K
Kozlov Dmitry 已提交
139
static int send_pptp_stop_ctrl_conn_rply(struct pptp_conn_t *conn, int reason, int err_code)
140
{
K
Kozlov Dmitry 已提交
141 142 143 144
	struct pptp_stop_ctrl_conn msg = {
		.header = PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RPLY),
		.reason_result = hton8(reason),
		.error_code = hton8(err_code),
145 146
	};

K
Kozlov Dmitry 已提交
147 148 149
	if (conf_verbose)
		log_ppp_info("send [PPTP Stop-Ctrl-Conn-Reply <Result %i> <Error %i>]\n", msg.reason_result, msg.error_code);

K
Kozlov Dmitry 已提交
150
	return post_msg(conn, &msg, sizeof(msg));
151 152 153
}
static int pptp_stop_ctrl_conn_rqst(struct pptp_conn_t *conn)
{
K
Kozlov Dmitry 已提交
154
	struct pptp_stop_ctrl_conn *msg = (struct pptp_stop_ctrl_conn *)conn->in_buf;
K
Kozlov Dmitry 已提交
155 156
	if (conf_verbose)
		log_ppp_info("recv [PPTP Stop-Ctrl-Conn-Request <Reason %i>]\n", msg->reason_result);
157

K
Kozlov Dmitry 已提交
158
	send_pptp_stop_ctrl_conn_rply(conn, PPTP_CONN_STOP_OK, 0);
K
Kozlov Dmitry 已提交
159 160 161 162 163

	return -1;
}

static int pptp_stop_ctrl_conn_rply(struct pptp_conn_t *conn)
K
Kozlov Dmitry 已提交
164 165 166 167
{	
	struct pptp_stop_ctrl_conn *msg = (struct pptp_stop_ctrl_conn*)conn->in_buf;
	if (conf_verbose)
		log_ppp_info("recv [PPTP Stop-Ctrl-Conn-Reply <Result %i> <Error %i>]\n", msg->reason_result, msg->error_code);
K
Kozlov Dmitry 已提交
168
	return -1;
169 170
}

K
Kozlov Dmitry 已提交
171
static int send_pptp_start_ctrl_conn_rply(struct pptp_conn_t *conn, int res_code, int err_code)
172
{
K
Kozlov Dmitry 已提交
173 174 175 176 177
	struct pptp_start_ctrl_conn msg = {
		.header = PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RPLY),
		.version = htons(PPTP_VERSION),
		.result_code = res_code,
		.error_code = err_code,
K
Kozlov Dmitry 已提交
178 179
		.framing_cap = htonl(3),
		.bearer_cap = htonl(3),
K
Kozlov Dmitry 已提交
180 181
		.max_channels = htons(1),
		.firmware_rev = htons(PPTP_FIRMWARE_VERSION),
182 183
	};

K
Kozlov Dmitry 已提交
184 185
	memset(msg.hostname, 0, sizeof(msg.hostname));
	strcpy((char*)msg.hostname, PPTP_HOSTNAME);
186

K
Kozlov Dmitry 已提交
187 188
	memset(msg.vendor, 0, sizeof(msg.vendor));
	strcpy((char*)msg.vendor, PPTP_VENDOR);
189

K
Kozlov Dmitry 已提交
190 191 192
	if (conf_verbose)
		log_ppp_info("send [PPTP Start-Ctrl-Conn-Reply <Version %i> <Result %i> <Error %i> <Framing %x> <Bearer %x> <Max-Chan %i>]\n", msg.version, msg.result_code, msg.error_code, ntohl(msg.framing_cap), ntohl(msg.bearer_cap), ntohs(msg.max_channels));

K
Kozlov Dmitry 已提交
193
	return post_msg(conn, &msg, sizeof(msg));
194
}
K
Kozlov Dmitry 已提交
195

196 197
static int pptp_start_ctrl_conn_rqst(struct pptp_conn_t *conn)
{
K
Kozlov Dmitry 已提交
198
	struct pptp_start_ctrl_conn *msg = (struct pptp_start_ctrl_conn *)conn->in_buf;
199

K
Kozlov Dmitry 已提交
200 201 202
	if (conf_verbose)
		log_ppp_info("recv [PPTP Start-Ctrl-Conn-Request <Version %i> <Framing %x> <Bearer %x> <Max-Chan %i>]\n", msg->version, ntohl(msg->framing_cap), ntohl(msg->bearer_cap), ntohs(msg->max_channels));

K
Kozlov Dmitry 已提交
203
	if (conn->state != STATE_IDLE) {
204
		log_ppp_warn("unexpected PPTP_START_CTRL_CONN_RQST\n");
K
Kozlov Dmitry 已提交
205
		if (send_pptp_start_ctrl_conn_rply(conn, PPTP_CONN_RES_EXISTS, 0))
206 207 208 209
			return -1;
		return 0;
	}

K
Kozlov Dmitry 已提交
210
	if (msg->version != htons(PPTP_VERSION)) {
211
		log_ppp_warn("PPTP version mismatch: expecting %x, received %s\n", PPTP_VERSION, msg->version);
K
Kozlov Dmitry 已提交
212
		if (send_pptp_start_ctrl_conn_rply(conn, PPTP_CONN_RES_PROTOCOL, 0))
213 214 215
			return -1;
		return 0;
	}
K
Kozlov Dmitry 已提交
216
	/*if (!(ntohl(msg->framing_cap) & PPTP_FRAME_SYNC)) {
217
		log_ppp_warn("connection does not supports sync mode\n");
K
Kozlov Dmitry 已提交
218
		if (send_pptp_start_ctrl_conn_rply(conn, PPTP_CONN_RES_GE, 0))
219 220
			return -1;
		return 0;
K
Kozlov Dmitry 已提交
221
	}*/
K
Kozlov Dmitry 已提交
222
	if (send_pptp_start_ctrl_conn_rply(conn, PPTP_CONN_RES_SUCCESS, 0))
223 224
		return -1;

225 226
	triton_timer_mod(&conn->timeout_timer, 0);

K
Kozlov Dmitry 已提交
227
	conn->state = STATE_ESTB;
228 229 230 231

	return 0;
}

K
Kozlov Dmitry 已提交
232
static int send_pptp_out_call_rply(struct pptp_conn_t *conn, struct pptp_out_call_rqst *rqst, int call_id, int res_code, int err_code)
233
{
K
Kozlov Dmitry 已提交
234 235 236 237 238 239 240 241 242 243 244
	struct pptp_out_call_rply msg = {
		.header = PPTP_HEADER_CTRL(PPTP_OUT_CALL_RPLY),
		.call_id = htons(call_id),
		.call_id_peer = rqst->call_id,
		.result_code = res_code,
		.error_code = err_code,
		.cause_code = 0,
		.speed = rqst->bps_max,
		.recv_size = rqst->recv_size,
		.delay = 0,
		.channel = 0,
245 246
	};

K
Kozlov Dmitry 已提交
247 248 249
	if (conf_verbose)
		log_ppp_info("send [PPTP Outgoing-Call-Reply <Call-ID %x> <Peer-Call-ID %x> <Result %i> <Error %i> <Cause %i> <Speed %i> <Window-Size %i> <Delay %i> <Channel %x>]\n", ntohs(msg.call_id), ntohs(msg.call_id_peer), msg.result_code, msg.error_code, ntohs(msg.cause_code), ntohl(msg.speed), ntohs(msg.recv_size), ntohs(msg.delay), ntohl(msg.channel));

K
Kozlov Dmitry 已提交
250
	return post_msg(conn, &msg, sizeof(msg));
251 252 253 254
}

static int pptp_out_call_rqst(struct pptp_conn_t *conn)
{
K
Kozlov Dmitry 已提交
255 256
	struct pptp_out_call_rqst *msg = (struct pptp_out_call_rqst *)conn->in_buf;
	struct sockaddr_pppox src_addr, dst_addr;
257 258 259 260
  struct sockaddr_in addr;
	socklen_t addrlen;
	int pptp_sock;

K
Kozlov Dmitry 已提交
261 262 263
	if (conf_verbose)
		log_ppp_info("recv [PPTP Outgoing-Call-Request <Call-ID %x> <Call-Serial %x> <Min-BPS %i> <Max-BPS %i> <Bearer %x> <Framing %x> <Window-Size %i> <Delay %i>]\n", ntohs(msg->call_id), ntohs(msg->call_sernum), ntohl(msg->bps_min), ntohl(msg->bps_max), ntohl(msg->bearer), ntohl(msg->framing), ntohs(msg->recv_size), ntohs(msg->delay));

K
Kozlov Dmitry 已提交
264
	if (conn->state != STATE_ESTB) {
265
		log_ppp_warn("unexpected PPTP_OUT_CALL_RQST\n");
K
Kozlov Dmitry 已提交
266
		if (send_pptp_out_call_rply(conn, msg, 0, PPTP_CALL_RES_GE, PPTP_GE_NOCONN))
267 268 269 270
			return -1;
		return 0;
	}

K
Kozlov Dmitry 已提交
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
	src_addr.sa_family = AF_PPPOX;
	src_addr.sa_protocol = PX_PROTO_PPTP;
	src_addr.sa_addr.pptp.call_id = 0;
	addrlen = sizeof(addr);
	getsockname(conn->hnd.fd, (struct sockaddr*)&addr, &addrlen);
	src_addr.sa_addr.pptp.sin_addr = addr.sin_addr;

	dst_addr.sa_family = AF_PPPOX;
	dst_addr.sa_protocol = PX_PROTO_PPTP;
	dst_addr.sa_addr.pptp.call_id = htons(msg->call_id);
	addrlen = sizeof(addr);
	getpeername(conn->hnd.fd, (struct sockaddr*)&addr, &addrlen);
	dst_addr.sa_addr.pptp.sin_addr = addr.sin_addr;

	pptp_sock = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_PPTP);
	if (pptp_sock < 0) {
287
		log_ppp_error("failed to create PPTP socket (%s)\n", strerror(errno));
288 289
		return -1;
	}
K
Kozlov Dmitry 已提交
290
	if (bind(pptp_sock, (struct sockaddr*)&src_addr, sizeof(src_addr))) {
291
		log_ppp_error("failed to bind PPTP socket (%s)\n", strerror(errno));
292 293 294
		close(pptp_sock);
		return -1;
	}
K
Kozlov Dmitry 已提交
295 296
	addrlen = sizeof(src_addr);
	getsockname(pptp_sock, (struct sockaddr*)&src_addr, &addrlen);
297

K
Kozlov Dmitry 已提交
298
	if (connect(pptp_sock, (struct sockaddr*)&dst_addr, sizeof(dst_addr))) {
299
		log_ppp_error("failed to connect PPTP socket (%s)\n", strerror(errno));
300 301 302 303
		close(pptp_sock);
		return -1;
	}

K
Kozlov Dmitry 已提交
304
	if (send_pptp_out_call_rply(conn, msg, src_addr.sa_addr.pptp.call_id, PPTP_CALL_RES_OK, 0))
305 306
		return -1;

K
Kozlov Dmitry 已提交
307 308
	conn->call_id = src_addr.sa_addr.pptp.call_id;
	conn->peer_call_id = msg->call_id;
K
Kozlov Dmitry 已提交
309
	conn->ppp.fd = pptp_sock;
D
Dmitry Kozlov 已提交
310
	conn->ppp.chan_name = _strdup(inet_ntoa(dst_addr.sa_addr.pptp.sin_addr));
311 312 313

	triton_event_fire(EV_CTRL_STARTED, &conn->ppp);

K
Kozlov Dmitry 已提交
314
	if (establish_ppp(&conn->ppp)) {
315
		close(pptp_sock);
K
Kozlov Dmitry 已提交
316 317 318
		//if (send_pptp_stop_ctrl_conn_rqst(conn, 0, 0))
		conn->state = STATE_FIN;
		return -1;
319 320 321
	}
	conn->state = STATE_PPP;
	
322 323
	if (conn->timeout_timer.tpd)
		triton_timer_del(&conn->timeout_timer);
324 325 326 327 328 329 330 331 332

	if (conf_echo_interval) {
		conn->echo_timer.period = conf_echo_interval * 1000;
		triton_timer_add(&conn->ctx, &conn->echo_timer, 0);
	}

	return 0;
}

333
static int send_pptp_call_disconnect_notify(struct pptp_conn_t *conn, int result)
K
Kozlov Dmitry 已提交
334 335 336 337 338 339 340 341 342 343
{
	struct pptp_call_clear_ntfy msg = {
		.header = PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_NTFY),
		.call_id = htons(conn->peer_call_id),
		.result_code = result,
		.error_code = 0,
		.cause_code = 0,
	};

	if (conf_verbose)
344
		log_ppp_info("send [PPTP Call-Disconnect-Notify <Call-ID %x> <Result %i> <Error %i> <Cause %i>]\n", ntohs(msg.call_id), msg.result_code, msg.error_code, msg.cause_code);
K
Kozlov Dmitry 已提交
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
	
	return post_msg(conn, &msg, sizeof(msg));
}

static int pptp_call_clear_rqst(struct pptp_conn_t *conn)
{
	struct pptp_call_clear_rqst *rqst = (struct pptp_call_clear_rqst *)conn->in_buf;

	if (conf_verbose)
		log_ppp_info("recv [PPTP Call-Clear-Request <Call-ID %x>]\n", ntohs(rqst->call_id));

	if (conn->state == STATE_PPP) {
		conn->state = STATE_CLOSE;
		ppp_terminate(&conn->ppp, 1);
	}

361
	return send_pptp_call_disconnect_notify(conn, 4);
K
Kozlov Dmitry 已提交
362 363
}

364 365 366 367
static int pptp_echo_rqst(struct pptp_conn_t *conn)
{
	struct pptp_echo_rqst *in_msg = (struct pptp_echo_rqst *)conn->in_buf;
	struct pptp_echo_rply out_msg = {
K
Kozlov Dmitry 已提交
368
		.header = PPTP_HEADER_CTRL(PPTP_ECHO_RPLY),
369 370 371 372
		.identifier = in_msg->identifier,
		.result_code = 1,
	};

K
Kozlov Dmitry 已提交
373 374 375 376 377
	if (conf_verbose) {
		log_ppp_info("recv [PPTP Echo-Request <Identifier %x>]\n", in_msg->identifier);
		log_ppp_info("send [PPTP Echo-Reply <Identifier %x>]\n", out_msg.identifier);
	}

378 379
	return post_msg(conn, &out_msg, sizeof(out_msg));
}
380

381 382 383
static int pptp_echo_rply(struct pptp_conn_t *conn)
{
	struct pptp_echo_rply *msg = (struct pptp_echo_rply *)conn->in_buf;
K
Kozlov Dmitry 已提交
384 385 386 387
	
	if (conf_verbose)
		log_ppp_info("recv [PPTP Echo-Reply <Identifier %x>]\n", msg->identifier);

388
	if (msg->identifier != conn->echo_sent) {
389
		log_ppp_warn("pptp:echo: identifier mismatch\n");
D
Dmitry Kozlov 已提交
390
		//return -1;
391 392
	}
	conn->echo_sent = 0;
393 394
	return 0;
}
395 396 397 398 399 400 401
static void pptp_send_echo(struct triton_timer_t *t)
{
	struct pptp_conn_t *conn = container_of(t, typeof(*conn), echo_timer);
	struct pptp_echo_rqst msg = {
		.header = PPTP_HEADER_CTRL(PPTP_ECHO_RQST),
	};

K
Kozlov Dmitry 已提交
402
	if (++conn->echo_sent == conf_echo_failure) {
403
		log_ppp_warn("pptp: no echo reply\n");
404 405 406 407 408 409 410
		disconnect(conn);
		return;
	}

	conn->echo_sent = random();
	msg.identifier = conn->echo_sent;

K
Kozlov Dmitry 已提交
411 412 413
	if (conf_verbose)
		log_ppp_info("send [PPTP Echo-Request <Identifier %x>]\n", msg.identifier);

414 415 416
	if (post_msg(conn, &msg, sizeof(msg)))
		disconnect(conn);
}
417 418 419

static int process_packet(struct pptp_conn_t *conn)
{
K
Kozlov Dmitry 已提交
420
	struct pptp_header *hdr = (struct pptp_header *)conn->in_buf;
421 422 423 424 425 426
	switch(ntohs(hdr->ctrl_type))
	{
		case PPTP_START_CTRL_CONN_RQST:
			return pptp_start_ctrl_conn_rqst(conn);
		case PPTP_STOP_CTRL_CONN_RQST:
			return pptp_stop_ctrl_conn_rqst(conn);
K
Kozlov Dmitry 已提交
427 428
		case PPTP_STOP_CTRL_CONN_RPLY:
			return pptp_stop_ctrl_conn_rply(conn);
429 430
		case PPTP_OUT_CALL_RQST:
			return pptp_out_call_rqst(conn);
431 432 433 434
		case PPTP_ECHO_RQST:
			return pptp_echo_rqst(conn);
		case PPTP_ECHO_RPLY:
			return pptp_echo_rply(conn);
K
Kozlov Dmitry 已提交
435 436
		case PPTP_CALL_CLEAR_RQST:
			return pptp_call_clear_rqst(conn);
K
Kozlov Dmitry 已提交
437 438 439 440
		case PPTP_SET_LINK_INFO:
			if (conf_verbose)
				log_ppp_info("recv [PPTP Set-Link-Info]\n");
			return 0;
K
Kozlov Dmitry 已提交
441 442
		default:
			log_ppp_warn("recv [PPTP Unknown (%x)]\n", ntohs(hdr->ctrl_type));
443 444 445 446
	}
	return 0;
}

K
Kozlov Dmitry 已提交
447
static int pptp_read(struct triton_md_handler_t *h)
448
{
449
	struct pptp_conn_t *conn=container_of(h,typeof(*conn),hnd);
450 451 452
	struct pptp_header *hdr=(struct pptp_header *)conn->in_buf;
	int n;

K
Kozlov Dmitry 已提交
453
	while(1) {
K
Kozlov Dmitry 已提交
454
		n = read(h->fd, conn->in_buf + conn->in_size, PPTP_CTRL_SIZE_MAX - conn->in_size);
K
Kozlov Dmitry 已提交
455
		if (n < 0) {
K
Kozlov Dmitry 已提交
456 457 458 459
			if (errno == EINTR)
				continue;
			if (errno == EAGAIN)
				return 0;
460
			log_ppp_error("pptp: read: %s\n",strerror(errno));
K
Kozlov Dmitry 已提交
461 462
			goto drop;
		}
K
Kozlov Dmitry 已提交
463 464
		if (n == 0)
			goto drop;
K
Kozlov Dmitry 已提交
465 466
		conn->in_size += n;
		if (conn->in_size >= sizeof(*hdr)) {
K
Kozlov Dmitry 已提交
467 468
			if (hdr->magic != htonl(PPTP_MAGIC)) {
				log_ppp_error("pptp: invalid magic\n");
K
Kozlov Dmitry 已提交
469
				goto drop;
K
Kozlov Dmitry 已提交
470 471 472
			}
			if (ntohs(hdr->length) >= PPTP_CTRL_SIZE_MAX) {
				log_ppp_error("pptp: message is too long\n");
K
Kozlov Dmitry 已提交
473
				goto drop;
K
Kozlov Dmitry 已提交
474
			}
K
Kozlov Dmitry 已提交
475
			if (ntohs(hdr->length) > conn->in_size)
K
Kozlov Dmitry 已提交
476 477 478 479
				continue;
			if (ntohs(hdr->length) <= conn->in_size) {
				if (ntohs(hdr->length) != PPTP_CTRL_SIZE(ntohs(hdr->ctrl_type))) {
					log_ppp_error("pptp: invalid message length\n");
K
Kozlov Dmitry 已提交
480
					goto drop;
K
Kozlov Dmitry 已提交
481
				}
K
Kozlov Dmitry 已提交
482 483
				if (process_packet(conn))
					goto drop;
K
Kozlov Dmitry 已提交
484 485 486
				conn->in_size -= ntohs(hdr->length);
				if (conn->in_size)
					memmove(conn->in_buf, conn->in_buf + ntohs(hdr->length), conn->in_size);
K
Kozlov Dmitry 已提交
487
			}
488 489 490 491
		}
	}
drop:
	disconnect(conn);
K
Kozlov Dmitry 已提交
492
	return 1;
493
}
K
Kozlov Dmitry 已提交
494
static int pptp_write(struct triton_md_handler_t *h)
495
{
K
Kozlov Dmitry 已提交
496 497
	struct pptp_conn_t *conn = container_of(h, typeof(*conn), hnd);
	int n;
498

K
Kozlov Dmitry 已提交
499 500 501 502 503 504 505 506 507 508
	while (1) {
		n = write(h->fd, conn->out_buf+conn->out_pos, conn->out_size-conn->out_pos);

		if (n < 0) {
			if (errno == EINTR)
				continue;
			if (errno == EAGAIN)
				n = 0;
			else {
				if (errno != EPIPE)
509
					log_ppp_error("pptp:post_msg: %s\n", strerror(errno));
K
Kozlov Dmitry 已提交
510 511 512
				disconnect(conn);
				return 1;
			}
513 514
		}

K
Kozlov Dmitry 已提交
515 516 517 518 519 520 521
		conn->out_pos += n;
		if (conn->out_pos == conn->out_size) {
			conn->out_pos = 0;
			conn->out_size = 0;
			triton_md_disable_handler(h, MD_MODE_WRITE);
			return 0;
		}
522 523
	}
}
524
static void pptp_timeout(struct triton_timer_t *t)
525
{
526 527
	struct pptp_conn_t *conn = container_of(t, typeof(*conn), timeout_timer);
	disconnect(conn);
528
}
529
static void pptp_close(struct triton_context_t *ctx)
K
Kozlov Dmitry 已提交
530
{
K
Kozlov Dmitry 已提交
531 532
	struct pptp_conn_t *conn = container_of(ctx, typeof(*conn), ctx);
	if (conn->state == STATE_PPP) {
K
Kozlov Dmitry 已提交
533
		conn->state = STATE_CLOSE;
534 535 536 537 538
		ppp_terminate(&conn->ppp, 1);
		if (send_pptp_call_disconnect_notify(conn, 3)) {
			triton_context_call(&conn->ctx, (void (*)(void*))disconnect, conn);
			return;
		}
K
Kozlov Dmitry 已提交
539
	} else {
540
		if (send_pptp_stop_ctrl_conn_rqst(conn, 0)) {
K
Kozlov Dmitry 已提交
541
			triton_context_call(&conn->ctx, (void (*)(void*))disconnect, conn);
542
			return;
K
Kozlov Dmitry 已提交
543 544
		}
	}
545 546 547 548 549

	if (conn->timeout_timer.tpd)
		triton_timer_mod(&conn->timeout_timer, 0);
	else
		triton_timer_add(ctx, &conn->timeout_timer, 0);
K
Kozlov Dmitry 已提交
550
}
551 552
static void ppp_started(struct ppp_t *ppp)
{
553
	log_ppp_debug("ppp_started\n");
554 555 556
}
static void ppp_finished(struct ppp_t *ppp)
{
K
Kozlov Dmitry 已提交
557
	struct pptp_conn_t *conn = container_of(ppp, typeof(*conn), ppp);
558

K
Kozlov Dmitry 已提交
559
	if (conn->state != STATE_CLOSE) {
560
		log_ppp_debug("ppp_finished\n");
K
Kozlov Dmitry 已提交
561
		conn->state = STATE_CLOSE;
K
Kozlov Dmitry 已提交
562

563
		if (send_pptp_call_disconnect_notify(conn, 3))
K
Kozlov Dmitry 已提交
564 565
			triton_context_call(&conn->ctx, (void (*)(void*))disconnect, conn);
		else if (send_pptp_stop_ctrl_conn_rqst(conn, 0))
K
Kozlov Dmitry 已提交
566 567 568 569 570 571 572
			triton_context_call(&conn->ctx, (void (*)(void*))disconnect, conn);
		else {
			if (conn->timeout_timer.tpd)
				triton_timer_mod(&conn->timeout_timer, 0);
			else
				triton_timer_add(&conn->ctx, &conn->timeout_timer, 0);
		}
K
Kozlov Dmitry 已提交
573
	}
574
}
K
Kozlov Dmitry 已提交
575 576 577

//==================================

K
Kozlov Dmitry 已提交
578 579
struct pptp_serv_t
{
580
	struct triton_context_t ctx;
K
Kozlov Dmitry 已提交
581 582 583
	struct triton_md_handler_t hnd;
};

K
Kozlov Dmitry 已提交
584 585 586
static int pptp_connect(struct triton_md_handler_t *h)
{
  struct sockaddr_in addr;
K
Kozlov Dmitry 已提交
587
	socklen_t size = sizeof(addr);
K
Kozlov Dmitry 已提交
588 589 590
	int sock;
	struct pptp_conn_t *conn;

K
Kozlov Dmitry 已提交
591 592 593 594
	while(1) {
		sock = accept(h->fd, (struct sockaddr *)&addr, &size);
		if (sock < 0) {
			if (errno == EAGAIN)
K
Kozlov Dmitry 已提交
595
				return 0;
K
Kozlov Dmitry 已提交
596 597 598 599 600 601
			log_error("pptp: accept failed: %s\n", strerror(errno));
			continue;
		}

		log_info("pptp: new connection from %s\n", inet_ntoa(addr.sin_addr));

602 603 604 605 606 607
		if (iprange_client_check(addr.sin_addr.s_addr)) {
			log_warn("pptp: IP is out of client-ip-range, droping connection...\n");
			close(sock);
			continue;
		}

K
Kozlov Dmitry 已提交
608 609 610 611
		if (fcntl(sock, F_SETFL, O_NONBLOCK)) {
			log_error("pptp: failed to set nonblocking mode: %s, closing connection...\n", strerror(errno));
			close(sock);
			continue;
K
Kozlov Dmitry 已提交
612
		}
K
Kozlov Dmitry 已提交
613

614
		conn = mempool_alloc(conn_pool);
K
Kozlov Dmitry 已提交
615 616 617 618 619
		memset(conn, 0, sizeof(*conn));
		conn->hnd.fd = sock;
		conn->hnd.read = pptp_read;
		conn->hnd.write = pptp_write;
		conn->ctx.close = pptp_close;
620
		conn->ctx.before_switch = log_switch;
D
Dmitry Kozlov 已提交
621 622
		conn->in_buf = _malloc(PPTP_CTRL_SIZE_MAX);
		conn->out_buf = _malloc(PPTP_CTRL_SIZE_MAX);
623 624 625
		conn->timeout_timer.expire = pptp_timeout;
		conn->timeout_timer.period = conf_timeout * 1000;
		conn->echo_timer.expire = pptp_send_echo;
626 627 628
		conn->ctrl.ctx = &conn->ctx;
		conn->ctrl.started = ppp_started;
		conn->ctrl.finished = ppp_finished;
629 630 631 632 633 634 635
		conn->ctrl.max_mtu = PPTP_MAX_MTU;
		
		conn->ctrl.calling_station_id = _malloc(17);
		conn->ctrl.called_station_id = _malloc(17);
		u_inet_ntoa(addr.sin_addr.s_addr, conn->ctrl.calling_station_id);
		getsockname(sock, &addr, &size);
		u_inet_ntoa(addr.sin_addr.s_addr, conn->ctrl.called_station_id);
636 637 638
	
		ppp_init(&conn->ppp);
		conn->ppp.ctrl = &conn->ctrl;
K
Kozlov Dmitry 已提交
639

640
		triton_context_register(&conn->ctx, &conn->ppp);
641 642
		conn->ctx.fname=__FILE__;
		conn->ctx.line=__LINE__;
K
Kozlov Dmitry 已提交
643
		triton_md_register_handler(&conn->ctx, &conn->hnd);
K
Kozlov Dmitry 已提交
644
		triton_md_enable_handler(&conn->hnd,MD_MODE_READ);
645
		triton_timer_add(&conn->ctx, &conn->timeout_timer, 0);
K
Kozlov Dmitry 已提交
646
		triton_context_wakeup(&conn->ctx);
647 648

		triton_event_fire(EV_CTRL_STARTING, &conn->ppp);
K
Kozlov Dmitry 已提交
649
	}
D
Dmitry Kozlov 已提交
650
	return 0;
K
Kozlov Dmitry 已提交
651
}
652
static void pptp_serv_close(struct triton_context_t *ctx)
K
Kozlov Dmitry 已提交
653
{
K
Kozlov Dmitry 已提交
654 655 656
	struct pptp_serv_t *s=container_of(ctx,typeof(*s),ctx);
	triton_md_unregister_handler(&s->hnd);
	close(s->hnd.fd);
K
Kozlov Dmitry 已提交
657
	triton_context_unregister(ctx);
K
Kozlov Dmitry 已提交
658 659 660 661 662
}

static struct pptp_serv_t serv=
{
	.hnd.read=pptp_connect,
K
Kozlov Dmitry 已提交
663
	.ctx.close=pptp_serv_close,
K
Kozlov Dmitry 已提交
664 665
};

K
Kozlov Dmitry 已提交
666
static void __init pptp_init(void)
K
Kozlov Dmitry 已提交
667 668
{
  struct sockaddr_in addr;
669
	char *opt;
K
Kozlov Dmitry 已提交
670
	
K
Kozlov Dmitry 已提交
671 672
	serv.hnd.fd = socket (PF_INET, SOCK_STREAM, 0);
  if (serv.hnd.fd < 0) {
673
    log_emerg("pptp: failed to create server socket: %s\n", strerror(errno));
K
Kozlov Dmitry 已提交
674 675 676 677 678
    return;
  }
  addr.sin_family = AF_INET;
  addr.sin_port = htons (PPTP_PORT);
  addr.sin_addr.s_addr = htonl (INADDR_ANY);
K
Kozlov Dmitry 已提交
679 680
  
  setsockopt(serv.hnd.fd, SOL_SOCKET, SO_REUSEADDR, &serv.hnd.fd, 4);  
K
Kozlov Dmitry 已提交
681
  if (bind (serv.hnd.fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) {
682
    log_emerg("pptp: failed to bind socket: %s\n", strerror(errno));
K
Kozlov Dmitry 已提交
683 684 685 686
		close(serv.hnd.fd);
    return;
  }

K
Kozlov Dmitry 已提交
687
  if (listen (serv.hnd.fd, 100) < 0) {
688
    log_emerg("pptp: failed to listen socket: %s\n", strerror(errno));
K
Kozlov Dmitry 已提交
689
		close(serv.hnd.fd);
K
Kozlov Dmitry 已提交
690
    return;
K
Kozlov Dmitry 已提交
691
  }
K
Kozlov Dmitry 已提交
692 693

	if (fcntl(serv.hnd.fd, F_SETFL, O_NONBLOCK)) {
694
    log_emerg("pptp: failed to set nonblocking mode: %s\n", strerror(errno));
K
Kozlov Dmitry 已提交
695 696 697
		close(serv.hnd.fd);
    return;
	}
K
Kozlov Dmitry 已提交
698
	
699 700 701 702 703
	opt = conf_get_opt("pptp", "timeout");
	if (opt && atoi(opt) > 0)
		conf_timeout = atoi(opt);
	
	opt = conf_get_opt("pptp", "echo-interval");
K
Kozlov Dmitry 已提交
704
	if (opt && atoi(opt) >= 0)
705
		conf_echo_interval = atoi(opt);
K
Kozlov Dmitry 已提交
706

K
Kozlov Dmitry 已提交
707 708 709 710 711 712 713 714
	opt = conf_get_opt("pptp", "echo-failure");
	if (opt && atoi(opt) > 0)
		conf_echo_failure = atoi(opt);

	opt = conf_get_opt("pptp", "verbose");
	if (opt && atoi(opt) > 0)
		conf_verbose = 1;

K
Kozlov Dmitry 已提交
715 716 717 718 719 720
	conn_pool = mempool_create(sizeof(struct pptp_conn_t));

	triton_context_register(&serv.ctx, NULL);
	triton_md_register_handler(&serv.ctx, &serv.hnd);
	triton_md_enable_handler(&serv.hnd, MD_MODE_READ);
	triton_context_wakeup(&serv.ctx);
K
Kozlov Dmitry 已提交
721 722
}