From aebda049dcd1999080d52c813a40cc85f8377d04 Mon Sep 17 00:00:00 2001 From: Kozlov Dmitry Date: Mon, 11 Oct 2010 18:19:37 +0400 Subject: started work on L2TPv2 server --- accel-pptpd/accel-pptp.conf | 6 +- accel-pptpd/ctrl/CMakeLists.txt | 12 +- accel-pptpd/ctrl/l2tp/CMakeLists.txt | 11 + accel-pptpd/ctrl/l2tp/attr_defs.h | 73 +++ accel-pptpd/ctrl/l2tp/dict.c | 271 ++++++++ accel-pptpd/ctrl/l2tp/dict/dictionary | 2 + accel-pptpd/ctrl/l2tp/dict/dictionary.rfc2661 | 55 ++ accel-pptpd/ctrl/l2tp/dict/dictionary.rfc3931 | 15 + accel-pptpd/ctrl/l2tp/dict2c.py | 20 + accel-pptpd/ctrl/l2tp/l2tp.c | 732 +++++++++++++++++++++ accel-pptpd/ctrl/l2tp/l2tp.h | 84 +++ accel-pptpd/ctrl/l2tp/l2tp_prot.h | 55 ++ accel-pptpd/ctrl/l2tp/packet.c | 457 +++++++++++++ accel-pptpd/ctrl/pppoe.c | 882 ------------------------- accel-pptpd/ctrl/pppoe.h | 59 -- accel-pptpd/ctrl/pppoe/CMakeLists.txt | 5 + accel-pptpd/ctrl/pppoe/pppoe.c | 890 ++++++++++++++++++++++++++ accel-pptpd/ctrl/pppoe/pppoe.h | 59 ++ accel-pptpd/ctrl/pptp.c | 736 --------------------- accel-pptpd/ctrl/pptp/CMakeLists.txt | 5 + accel-pptpd/ctrl/pptp/pptp.c | 736 +++++++++++++++++++++ accel-pptpd/ctrl/pptp/pptp_prot.h | 299 +++++++++ accel-pptpd/ctrl/pptp_prot.h | 299 --------- accel-pptpd/radius/CMakeLists.txt | 4 +- accel-pptpd/radius/acct.c | 2 + accel-pptpd/radius/dict.c | 10 +- accel-pptpd/radius/radius.c | 2 +- 27 files changed, 3787 insertions(+), 1994 deletions(-) create mode 100644 accel-pptpd/ctrl/l2tp/CMakeLists.txt create mode 100644 accel-pptpd/ctrl/l2tp/attr_defs.h create mode 100644 accel-pptpd/ctrl/l2tp/dict.c create mode 100644 accel-pptpd/ctrl/l2tp/dict/dictionary create mode 100644 accel-pptpd/ctrl/l2tp/dict/dictionary.rfc2661 create mode 100644 accel-pptpd/ctrl/l2tp/dict/dictionary.rfc3931 create mode 100644 accel-pptpd/ctrl/l2tp/dict2c.py create mode 100644 accel-pptpd/ctrl/l2tp/l2tp.c create mode 100644 accel-pptpd/ctrl/l2tp/l2tp.h create mode 100644 accel-pptpd/ctrl/l2tp/l2tp_prot.h create mode 100644 accel-pptpd/ctrl/l2tp/packet.c delete mode 100644 accel-pptpd/ctrl/pppoe.c delete mode 100644 accel-pptpd/ctrl/pppoe.h create mode 100644 accel-pptpd/ctrl/pppoe/CMakeLists.txt create mode 100644 accel-pptpd/ctrl/pppoe/pppoe.c create mode 100644 accel-pptpd/ctrl/pppoe/pppoe.h delete mode 100644 accel-pptpd/ctrl/pptp.c create mode 100644 accel-pptpd/ctrl/pptp/CMakeLists.txt create mode 100644 accel-pptpd/ctrl/pptp/pptp.c create mode 100644 accel-pptpd/ctrl/pptp/pptp_prot.h delete mode 100644 accel-pptpd/ctrl/pptp_prot.h (limited to 'accel-pptpd') diff --git a/accel-pptpd/accel-pptp.conf b/accel-pptpd/accel-pptp.conf index 8ca7c618..bf8cdd42 100644 --- a/accel-pptpd/accel-pptp.conf +++ b/accel-pptpd/accel-pptp.conf @@ -2,8 +2,9 @@ #path=/usr/local/lib/accel-pptp log_file #log_pgsql -pptp +#pptp #pppoe +l2tp auth_pap auth_chap_md5 auth_mschap_v1 @@ -31,6 +32,9 @@ echo-failure=3 echo-interval=30 verbose=1 +[ltp] +#dictionary=/usr/local/share/accel-pptp/dictionary + [pppoe] interface=eth0 verbose=1 diff --git a/accel-pptpd/ctrl/CMakeLists.txt b/accel-pptpd/ctrl/CMakeLists.txt index d63a825a..fa7acdc2 100644 --- a/accel-pptpd/ctrl/CMakeLists.txt +++ b/accel-pptpd/ctrl/CMakeLists.txt @@ -1,9 +1,3 @@ -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - -ADD_LIBRARY(pptp SHARED pptp.c) -ADD_LIBRARY(pppoe SHARED pppoe.c) - -INSTALL(TARGETS pptp pppoe - LIBRARY DESTINATION usr/lib/accel-pptp -) - +ADD_SUBDIRECTORY(pptp) +ADD_SUBDIRECTORY(pppoe) +#ADD_SUBDIRECTORY(l2tp) diff --git a/accel-pptpd/ctrl/l2tp/CMakeLists.txt b/accel-pptpd/ctrl/l2tp/CMakeLists.txt new file mode 100644 index 00000000..8a64d5f0 --- /dev/null +++ b/accel-pptpd/ctrl/l2tp/CMakeLists.txt @@ -0,0 +1,11 @@ +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +ADD_DEFINITIONS(-DDICTIONARY="${CMAKE_INSTALL_PREFIX}/usr/share/accel-pptp/l2tp/dictionary") + +ADD_LIBRARY(l2tp SHARED + l2tp.c + dict.c + packet.c +) + +INSTALL(TARGETS l2tp LIBRARY DESTINATION usr/lib/accel-pptp) diff --git a/accel-pptpd/ctrl/l2tp/attr_defs.h b/accel-pptpd/ctrl/l2tp/attr_defs.h new file mode 100644 index 00000000..e7991574 --- /dev/null +++ b/accel-pptpd/ctrl/l2tp/attr_defs.h @@ -0,0 +1,73 @@ +#ifndef __ATTR_DEFS_H +#define __ATTR_DEFS_H + +#define Message_Type 0 +#define Random_Vector 36 +#define Result_Code 1 +#define Protocol_Version 2 +#define Framing_Capabilities 3 +#define Bearer_Capabilities 4 +#define Tie_Breaker 5 +#define Firmware_Revision 6 +#define Host_Name 7 +#define Vendor_Name 8 +#define Assigned_Tunnel_ID 9 +#define Recv_Window_Size 10 +#define Challenge 11 +#define Challenge_Response 13 +#define Cause_Code 12 +#define Assigned_Session_ID 14 +#define Call_Serial_Number 15 +#define Minimum_BPS 16 +#define Maximum_BPS 17 +#define Bearer_Type 18 +#define Framing_Type 19 +#define Called_Number 21 +#define Calling_Number 22 +#define Sub_Address 23 +#define TX_Speed 24 +#define RX_Speed 38 +#define Physical_Channel_ID 25 +#define Private_Group_ID 37 +#define Sequencing_Required 39 +#define Init_Recv_LCP 26 +#define Last_Sent_LCP 27 +#define Last_Recv_LCP 28 +#define Proxy_Authen_Type 29 +#define Proxy_Authen_Name 30 +#define Proxy_Authen_Challenge 31 +#define Proxy_Authen_ID 32 +#define Proxy_Authen_Response 33 +#define Call_Errors 34 +#define ACCM 35 +#define Message_Type_Start_Ctrl_Conn_Request 1 +#define Message_Type_Start_Ctrl_Conn_Reply 2 +#define Message_Type_Start_Ctrl_Conn_Connected 3 +#define Message_Type_Stop_Ctrl_Conn_Notify 4 +#define Message_Type_Hello 6 +#define Message_Type_Outgoing_Call_Request 7 +#define Message_Type_Outgoing_Call_Reply 8 +#define Message_Type_Outgoing_Call_Connected 9 +#define Message_Type_Incoming_Call_Request 10 +#define Message_Type_Incoming_Call_Reply 11 +#define Message_Type_Incoming_Call_Connected 12 +#define Message_Type_Call_Disconnect_Notify 14 +#define Message_Type_WAN_Error_Notify 15 +#define Message_Type_Set_Link_Info 16 +#define Message_Digest 59 +#define Router_ID 60 +#define Assigned_Connection_ID 61 +#define Pseudowire_Capabilities 62 +#define Prefered_Language 72 +#define Local_Session_ID 63 +#define Remote_Session_ID 64 +#define Assigned_Cookie 65 +#define Remote_End_ID 66 +#define Pseudowire_Type 68 +#define L2_Specific_Sublayer 69 +#define Data_Sequencing 70 +#define TX_Connect_Speeed 74 +#define RX_Connect_Speeed 75 +#define Circuit_Status 71 + +#endif diff --git a/accel-pptpd/ctrl/l2tp/dict.c b/accel-pptpd/ctrl/l2tp/dict.c new file mode 100644 index 00000000..a0ca9999 --- /dev/null +++ b/accel-pptpd/ctrl/l2tp/dict.c @@ -0,0 +1,271 @@ +#include +#include +#include +#include +#include +#include + +#include "list.h" +#include "l2tp.h" +#include "log.h" +#include "triton.h" + +#include "memdebug.h" + +struct l2tp_dict_t +{ + struct list_head items; +}; + +static struct l2tp_dict_t *dict; + +#define BUF_SIZE 1024 +static char *path, *fname1, *buf; + +struct l2tp_dict_attr_t *l2tp_dict_find_attr_by_name(const char *name) +{ + struct l2tp_dict_attr_t *attr; + + list_for_each_entry(attr, &dict->items, entry) { + if (!strcmp(attr->name, name)) + return attr; + } + + return NULL; +} + +struct l2tp_dict_attr_t *l2tp_dict_find_attr_by_id(int id) +{ + struct l2tp_dict_attr_t *attr; + + list_for_each_entry(attr, &dict->items, entry) { + if (attr->id == id) + return attr; + } + + return NULL; +} + +struct l2tp_dict_value_t *l2tp_dict_find_value(struct l2tp_dict_attr_t *attr, l2tp_value_t val) +{ + struct l2tp_dict_value_t *v; + + list_for_each_entry(v, &attr->values, entry) { + switch (attr->type) { + case ATTR_TYPE_INT16: + if (v->val.int16 == val.int16) + return v; + break; + case ATTR_TYPE_INT32: + if (v->val.int32 == val.int32) + return v; + break; + } + } + + return NULL; +} + +static char *skip_word(char *ptr) +{ + for(; *ptr; ptr++) + if (*ptr == ' ' || *ptr == '\t' || *ptr == '\n') + break; + return ptr; +} + +static char *skip_space(char *ptr) +{ + for(; *ptr; ptr++) + if (*ptr != ' ' && *ptr != '\t') + break; + return ptr; +} + +static int split(char *buf, char **ptr) +{ + int i; + + for (i = 0; i < 6; i++) { + buf = skip_word(buf); + if (!*buf) + return i; + + *buf = 0; + + buf = skip_space(buf + 1); + if (!*buf) + return i; + + ptr[i] = buf; + } + + buf = skip_word(buf); + //if (*buf == '\n') + *buf = 0; + //else if (*buf) + // return -1; + + return i; +} + + +static int dict_load(const char *fname) +{ + FILE *f; + char *ptr[6], *endptr; + struct l2tp_dict_attr_t *attr; + struct l2tp_dict_value_t *value; + struct list_head *items; + int r, n, i; + + f = fopen(fname, "r"); + if (!f) { + log_emerg("l2tp: open '%s': %s\n", fname, strerror(errno)); + return -1; + } + + items = &dict->items; + while (fgets(buf, BUF_SIZE, f)) { + n++; + if (buf[0] == '#' || buf[0] == '\n' || buf[0] == 0) + continue; + + r = split(buf, ptr); + + if (!strcmp(buf, "$INCLUDE")) { + if (r != 1) + goto out_syntax; + + for (i = strlen(path) - 1; i; i--) { + if (path[i] == '/') { + path[i + 1] = 0; + break; + } + } + + strcpy(fname1, path); + strcat(fname1, ptr[0]); + + if (dict_load(fname1)) + goto out_err; + } else if (!strcmp(buf, "ATTRIBUTE")) { + if (r < 3) + goto out_syntax; + + attr = malloc(sizeof(*attr)); + memset(attr, 0, sizeof(*attr)); + list_add_tail(&attr->entry, items); + INIT_LIST_HEAD(&attr->values); + + attr->name = strdup(ptr[0]); + attr->id = strtol(ptr[1], &endptr, 10); + if (*endptr != 0) + goto out_syntax; + + if (!strcmp(ptr[2], "none")) + attr->type = ATTR_TYPE_NONE; + else if (!strcmp(ptr[2], "int16")) + attr->type = ATTR_TYPE_INT16; + else if (!strcmp(ptr[2], "int32")) + attr->type = ATTR_TYPE_INT32; + else if (!strcmp(ptr[2], "int64")) + attr->type = ATTR_TYPE_INT64; + else if (!strcmp(ptr[2], "octets")) + attr->type = ATTR_TYPE_OCTETS; + else if (!strcmp(ptr[2], "string")) + attr->type = ATTR_TYPE_STRING; + else + goto out_syntax; + + attr->M = -1; + attr->H = -1; + + for (i = 3; i < r; i++) { + if (!strcmp(ptr[i], "M=0")) + attr->M = 0; + else if (!strcmp(ptr[i], "M=1")) + attr->M = 1; + else if (!strcmp(ptr[i], "H=0")) + attr->H = 0; + else if (!strcmp(ptr[i], "H=1")) + attr->H = 1; + else + goto out_syntax; + } + } else if (!strcmp(buf, "VALUE")) { + if (r != 3) + goto out_syntax; + + attr = l2tp_dict_find_attr_by_name(ptr[0]); + if (!attr) { + log_emerg("l2tp:%s:%i: attribute not found\n", fname, n); + goto out_err; + } + + value = malloc(sizeof(*value)); + memset(value, 0, sizeof(*value)); + list_add_tail(&value->entry, &attr->values); + + value->name = strdup(ptr[1]); + switch (attr->type) { + case ATTR_TYPE_INT16: + case ATTR_TYPE_INT32: + value->val.int16 = strtol(ptr[2], &endptr, 10); + if (*endptr != 0) + goto out_syntax; + break; + case ATTR_TYPE_STRING: + value->val.string = strdup(ptr[2]); + break; + } + } else + goto out_syntax; + } + + fclose(f); + + return 0; + +out_syntax: + log_emerg("l2tp:%s:%i: syntaxis error\n", fname, n); +out_err: + fclose(f); + return -1; +} + +static int l2tp_dict_load(const char *fname) +{ + int r; + + dict = _malloc(sizeof(*dict)); + memset(dict, 0, sizeof(*dict)); + INIT_LIST_HEAD(&dict->items); + + path = _malloc(PATH_MAX); + fname1 = _malloc(PATH_MAX); + buf = _malloc(BUF_SIZE); + + strcpy(path, fname); + + r = dict_load(fname); + + _free(buf); + _free(fname1); + _free(path); + + return r; +} + +static void __init dict_init(void) +{ + char *opt; + + opt = conf_get_opt("l2tp", "dictionary"); + if (!opt) + opt = DICTIONARY; + + if (l2tp_dict_load(opt)) + _exit(EXIT_FAILURE); +} + diff --git a/accel-pptpd/ctrl/l2tp/dict/dictionary b/accel-pptpd/ctrl/l2tp/dict/dictionary new file mode 100644 index 00000000..f5d7c423 --- /dev/null +++ b/accel-pptpd/ctrl/l2tp/dict/dictionary @@ -0,0 +1,2 @@ +$INCLUDE dictionary.rfc2661 +$INCLUDE dictionary.rfc3931 diff --git a/accel-pptpd/ctrl/l2tp/dict/dictionary.rfc2661 b/accel-pptpd/ctrl/l2tp/dict/dictionary.rfc2661 new file mode 100644 index 00000000..434b55d9 --- /dev/null +++ b/accel-pptpd/ctrl/l2tp/dict/dictionary.rfc2661 @@ -0,0 +1,55 @@ +ATTRIBUTE Message-Type 0 int16 H=0 +ATTRIBUTE Random-Vector 36 octets M=1 H=0 +ATTRIBUTE Result-Code 1 octets M=1 H=0 +ATTRIBUTE Protocol-Version 2 int16 M=1 H=0 +ATTRIBUTE Framing-Capabilities 3 int32 M=1 +ATTRIBUTE Bearer-Capabilities 4 int32 M=1 +ATTRIBUTE Tie-Breaker 5 int64 M=1 +ATTRIBUTE Firmware-Revision 6 int16 M=0 +ATTRIBUTE Host-Name 7 string M=1 +ATTRIBUTE Vendor-Name 8 string M=0 +ATTRIBUTE Assigned-Tunnel-ID 9 int16 M=1 +ATTRIBUTE Recv-Window-Size 10 int16 M=1 +ATTRIBUTE Challenge 11 octets M=1 +ATTRIBUTE Challenge-Response 13 octets M=1 +ATTRIBUTE Cause-Code 12 int32 M=1 H=0 +ATTRIBUTE Assigned-Session-ID 14 int16 M=1 +ATTRIBUTE Call-Serial-Number 15 int32 M=1 +ATTRIBUTE Minimum-BPS 16 int32 M=1 +ATTRIBUTE Maximum-BPS 17 int32 M=1 +ATTRIBUTE Bearer-Type 18 int32 M=1 +ATTRIBUTE Framing-Type 19 int32 M=1 +ATTRIBUTE Called-Number 21 string M=1 +ATTRIBUTE Calling-Number 22 string M=1 +ATTRIBUTE Sub-Address 23 string M=1 +ATTRIBUTE TX-Speed 24 int32 M=1 +ATTRIBUTE RX-Speed 38 int32 M=1 +ATTRIBUTE Physical-Channel-ID 25 int32 M=0 +ATTRIBUTE Private-Group-ID 37 int32 M=0 +ATTRIBUTE Sequencing-Required 39 none M=1 H=0 +ATTRIBUTE Init-Recv-LCP 26 octets M=0 +ATTRIBUTE Last-Sent-LCP 27 octets M=0 +ATTRIBUTE Last-Recv-LCP 28 octets M=0 +ATTRIBUTE Proxy-Authen-Type 29 int16 M=0 +ATTRIBUTE Proxy-Authen-Name 30 string M=0 +ATTRIBUTE Proxy-Authen-Challenge 31 octets M=0 +ATTRIBUTE Proxy-Authen-ID 32 int16 M=0 +ATTRIBUTE Proxy-Authen-Response 33 octets M=0 +ATTRIBUTE Call-Errors 34 octets M=1 +ATTRIBUTE ACCM 35 octets M=1 + +VALUE Message-Type Start-Ctrl-Conn-Request 1 +VALUE Message-Type Start-Ctrl-Conn-Reply 2 +VALUE Message-Type Start-Ctrl-Conn-Connected 3 +VALUE Message-Type Stop-Ctrl-Conn-Notify 4 +VALUE Message-Type Hello 6 +VALUE Message-Type Outgoing-Call-Request 7 +VALUE Message-Type Outgoing-Call-Reply 8 +VALUE Message-Type Outgoing-Call-Connected 9 +VALUE Message-Type Incoming-Call-Request 10 +VALUE Message-Type Incoming-Call-Reply 11 +VALUE Message-Type Incoming-Call-Connected 12 +VALUE Message-Type Call-Disconnect-Notify 14 +VALUE Message-Type WAN-Error-Notify 15 +VALUE Message-Type Set-Link-Info 16 + diff --git a/accel-pptpd/ctrl/l2tp/dict/dictionary.rfc3931 b/accel-pptpd/ctrl/l2tp/dict/dictionary.rfc3931 new file mode 100644 index 00000000..d6ad410b --- /dev/null +++ b/accel-pptpd/ctrl/l2tp/dict/dictionary.rfc3931 @@ -0,0 +1,15 @@ +ATTRIBUTE Message-Digest 59 octets M=1 H=0 +ATTRIBUTE Router-ID 60 int32 H=0 +ATTRIBUTE Assigned-Connection-ID 61 int32 +ATTRIBUTE Pseudowire-Capabilities 62 octets +ATTRIBUTE Prefered-Language 72 octets +ATTRIBUTE Local-Session-ID 63 int32 +ATTRIBUTE Remote-Session-ID 64 int32 +ATTRIBUTE Assigned-Cookie 65 octets +ATTRIBUTE Remote-End-ID 66 octets +ATTRIBUTE Pseudowire-Type 68 int16 +ATTRIBUTE L2-Specific-Sublayer 69 int16 +ATTRIBUTE Data-Sequencing 70 int16 +ATTRIBUTE TX-Connect-Speeed 74 int64 +ATTRIBUTE RX-Connect-Speeed 75 int64 +ATTRIBUTE Circuit-Status 71 int16 diff --git a/accel-pptpd/ctrl/l2tp/dict2c.py b/accel-pptpd/ctrl/l2tp/dict2c.py new file mode 100644 index 00000000..ff0961e7 --- /dev/null +++ b/accel-pptpd/ctrl/l2tp/dict2c.py @@ -0,0 +1,20 @@ +import sys,re + +hdr = file(sys.argv[2],'w') + +def process(fname, hdr): + for line in file(fname): + if line[:-1].strip() == '': + continue + if line[0] == '#': + continue + f = re.compile('[$.a-zA-Z0-9\-]+').findall(line) + if f[0] == 'ATTRIBUTE' or f[0] == 'VENDOR': + hdr.write('#define {0} {1}\n'.format(f[1].replace('-','_').replace('.','_'), f[2])) + elif f[0] == 'VALUE': + hdr.write('#define {0}_{1} {2}\n'.format(f[1].replace('-','_').replace('.','_'), f[2].replace('-','_'),f[3])) + elif f[0] == '$INCLUDE': + process(f[1], hdr) + +if __name__ == '__main__': + process(sys.argv[1], hdr) diff --git a/accel-pptpd/ctrl/l2tp/l2tp.c b/accel-pptpd/ctrl/l2tp/l2tp.c new file mode 100644 index 00000000..7548411a --- /dev/null +++ b/accel-pptpd/ctrl/l2tp/l2tp.c @@ -0,0 +1,732 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "triton.h" +#include "mempool.h" +#include "log.h" +#include "ppp.h" +#include "events.h" +#include "utils.h" + +#include "memdebug.h" + +#include "l2tp.h" +#include "attr_defs.h" + +#define STATE_WAIT_SCCCN 1 +#define STATE_WAIT_OCRQ 2 +#define STATE_WAIT_OCCN 3 +#define STATE_PPP 4 +#define STATE_CLOSE 0 + +int conf_verbose = 0; +int conf_timeout = 5; +int conf_retransmit = 5; +const char *conf_host_name = "accel-pptp"; + +struct l2tp_serv_t +{ + struct triton_context_t ctx; + struct triton_md_handler_t hnd; + struct sockaddr_in addr; +}; + +struct l2tp_conn_t +{ + struct triton_context_t ctx; + struct triton_timer_t timeout_timer; + struct triton_timer_t echo_timer; + + pthread_mutex_t lock; + + int sock; + struct sockaddr_in addr; + uint16_t tid; + uint16_t sid; + uint16_t peer_tid; + uint16_t peer_sid; + uint32_t framing_cap; + + struct l2tp_packet_t *last_pack; + int retransmit; + uint16_t Ns, Nr; + struct list_head recv_queue; + struct list_head send_queue; + + int state; + + struct ppp_ctrl_t ctrl; + struct ppp_t ppp; +}; + +static pthread_mutex_t l2tp_lock = PTHREAD_MUTEX_INITIALIZER; +static struct l2tp_conn_t **l2tp_conn; +static uint16_t l2tp_tid; + +static mempool_t l2tp_conn_pool; + +static void l2tp_timeout(struct triton_timer_t *t); +static void l2tp_send_SCCRP(struct l2tp_conn_t *conn); +static void l2tp_send(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack); + +static struct l2tp_conn_t *l2tp_conn_lookup(uint16_t tid) +{ + struct l2tp_conn_t *conn; + pthread_mutex_lock(&conn->lock); + conn = l2tp_conn[tid]; + if (conn) + pthread_mutex_lock(&conn->lock); + pthread_mutex_unlock(&conn->lock); + + return conn; +} + +static void l2tp_disconnect(struct l2tp_conn_t *conn) +{ + close(conn->sock); + + if (conn->timeout_timer.tpd) + triton_timer_del(&conn->timeout_timer); + + if (conn->echo_timer.tpd) + triton_timer_del(&conn->echo_timer); + + if (conn->state == STATE_PPP) { + conn->state = STATE_CLOSE; + ppp_terminate(&conn->ppp, 1); + } + + pthread_mutex_lock(&l2tp_lock); + pthread_mutex_lock(&conn->lock); + l2tp_conn[conn->tid] = NULL; + pthread_mutex_unlock(&l2tp_lock); + pthread_mutex_unlock(&conn->lock); + + triton_event_fire(EV_CTRL_FINISHED, &conn->ppp); + + if (conf_verbose) + log_ppp_info("disconnected\n"); + + triton_context_unregister(&conn->ctx); + + if (conn->last_pack) + l2tp_packet_free(conn->last_pack); + + if (conn->ppp.chan_name) + _free(conn->ppp.chan_name); + + _free(conn->ctrl.calling_station_id); + _free(conn->ctrl.called_station_id); + + mempool_free(conn); +} + +static void l2tp_terminate(struct l2tp_conn_t *conn, int res, int err) +{ + struct l2tp_packet_t *pack; + struct l2tp_avp_result_code rc = {res, err}; + + pack = l2tp_packet_alloc(2, Message_Type_Stop_Ctrl_Conn_Notify, &conn->addr); + if (!pack) { + l2tp_disconnect(conn); + return; + } + + if (l2tp_packet_add_int16(pack, Assigned_Tunnel_ID, conn->tid)) + goto out_err; + if (l2tp_packet_add_octets(pack, Result_Code, (uint8_t *)&rc, sizeof(rc))) + goto out_err; + + l2tp_send(conn, pack); + + return; + +out_err: + l2tp_packet_free(pack); + l2tp_disconnect(conn); +} + +static void l2tp_alloc(struct l2tp_serv_t *serv, struct l2tp_packet_t *pack, struct l2tp_attr_t *assigned_tid, struct l2tp_attr_t *framing_cap) +{ + struct l2tp_conn_t *conn; + uint16_t tid; + + conn = mempool_alloc(l2tp_conn_pool); + if (!conn) { + log_emerg("l2tp: out of memory\n"); + return; + } + + memset(conn, 0, sizeof(*conn)); + + pthread_mutex_lock(&l2tp_lock); + for (tid = l2tp_tid + 1; tid != l2tp_tid; tid++) { + if (tid == L2TP_MAX_TID) + tid = 1; + if (!l2tp_conn[tid]) { + l2tp_conn[tid] = conn; + conn->tid = tid; + break; + } + } + pthread_mutex_unlock(&l2tp_lock); + + if (!conn->tid) { + if (conf_verbose) + log_warn("l2tp: no free tid available\n"); + mempool_free(conn); + return; + } + + INIT_LIST_HEAD(&conn->recv_queue); + INIT_LIST_HEAD(&conn->send_queue); + + conn->sock = dup(serv->hnd.fd); + memcpy(&conn->addr, &pack->addr, sizeof(pack->addr)); + conn->peer_tid = assigned_tid->val.uint16; + conn->framing_cap = framing_cap->val.uint32; + + conn->timeout_timer.expire = l2tp_timeout; + conn->timeout_timer.period = conf_timeout * 1000; + conn->ctrl.ctx = &conn->ctx; + conn->ctrl.name = "l2tp"; + + conn->ctrl.calling_station_id = _malloc(17); + conn->ctrl.called_station_id = _malloc(17); + u_inet_ntoa(conn->addr.sin_addr.s_addr, conn->ctrl.calling_station_id); + u_inet_ntoa(serv->addr.sin_addr.s_addr, conn->ctrl.called_station_id); + + ppp_init(&conn->ppp); + conn->ppp.ctrl = &conn->ctrl; + + triton_context_register(&conn->ctx, &conn->ppp); + triton_context_wakeup(&conn->ctx); + + if (conf_verbose) { + log_switch(&conn->ctx, &conn->ppp); + log_ppp_info("recv "); + l2tp_packet_print(pack); + } + + triton_context_call(&conn->ctx, (triton_event_func)l2tp_send_SCCRP, conn); +} + +static int l2tp_connect(struct l2tp_conn_t *conn) +{ + + return 0; +} + +static void l2tp_timeout(struct triton_timer_t *t) +{ + struct l2tp_conn_t *conn = container_of(t, typeof(*conn), timeout_timer); + struct l2tp_packet_t *pack; + + if (!list_empty(&conn->send_queue)) { + log_ppp_debug("l2tp: retransmit (%i)\n", conn->retransmit); + if (++conn->retransmit <= conf_retransmit) { + pack = list_entry(conn->send_queue.next, typeof(*pack), entry); + pack->hdr.Nr = htons(conn->Nr + 1); + if (conf_verbose) { + log_ppp_info("send "); + l2tp_packet_print(conn->last_pack); + } + if (l2tp_packet_send(conn->sock, conn->last_pack) == 0) + return; + } + } + + l2tp_disconnect(conn); +} + +static void l2tp_send(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) +{ + conn->retransmit = 0; + + pack->hdr.tid = htons(conn->peer_tid); + pack->hdr.sid = htons(conn->peer_sid); + pack->hdr.Nr = htons(conn->Nr + 1); + pack->hdr.Ns = htons(conn->Ns++); + + if (conf_verbose) { + log_ppp_info("send "); + l2tp_packet_print(conn->last_pack); + } + + if (l2tp_packet_send(conn->sock, pack)) + goto out_err; + + if (!conn->timeout_timer.tpd) + triton_timer_add(&conn->ctx, &conn->timeout_timer, 0); + + if (!list_empty(&pack->attrs)) + list_add_tail(&pack->entry, &conn->send_queue); + + return; + +out_err: + l2tp_packet_free(pack); + l2tp_disconnect(conn); +} + +static void l2tp_send_ZLB(struct l2tp_conn_t *conn) +{ + struct l2tp_packet_t *pack; + + pack = l2tp_packet_alloc(2, 0, &conn->addr); + if (!pack) { + l2tp_disconnect(conn); + return; + } + + l2tp_send(conn, pack); + + return; +} + +static void l2tp_send_SCCRP(struct l2tp_conn_t *conn) +{ + struct l2tp_packet_t *pack; + + pack = l2tp_packet_alloc(2, Message_Type_Start_Ctrl_Conn_Reply, &conn->addr); + if (!pack) { + l2tp_disconnect(conn); + return; + } + + if (l2tp_packet_add_int16(pack, Protocol_Version, L2TP_V2_PROTOCOL_VERSION)) + goto out_err; + if (l2tp_packet_add_string(pack, Host_Name, conf_host_name)) + goto out_err; + if (l2tp_packet_add_int32(pack, Framing_Capabilities, conn->framing_cap)) + goto out_err; + if (l2tp_packet_add_int16(pack, Assigned_Tunnel_ID, conn->tid)) + goto out_err; + + + l2tp_send(conn, pack); + + conn->state = STATE_WAIT_SCCCN; + + return; + +out_err: + l2tp_packet_free(pack); + l2tp_disconnect(conn); +} + +static void l2tp_send_OCRP(struct l2tp_conn_t *conn) +{ + struct l2tp_packet_t *pack; + + pack = l2tp_packet_alloc(2, Message_Type_Outgoing_Call_Reply, &conn->addr); + if (!pack) { + l2tp_disconnect(conn); + return; + } + + conn->sid = 1; + + if (l2tp_packet_add_int16(pack, Assigned_Session_ID, conn->sid)) + goto out_err; + + l2tp_send(conn, pack); + + return; + +out_err: + l2tp_packet_free(pack); + l2tp_disconnect(conn); +} + +static void l2tp_recv_SCCRQ(struct l2tp_serv_t *serv, struct l2tp_packet_t *pack) +{ + struct l2tp_attr_t *attr; + struct l2tp_attr_t *protocol_version = NULL; + struct l2tp_attr_t *assigned_tid = NULL; + struct l2tp_attr_t *assigned_cid = NULL; + struct l2tp_attr_t *framing_cap = NULL; + struct l2tp_attr_t *router_id = NULL; + + list_for_each_entry(attr, &pack->attrs, entry) { + switch (attr->attr->id) { + case Protocol_Version: + protocol_version = attr; + break; + case Framing_Capabilities: + framing_cap = attr; + break; + case Assigned_Tunnel_ID: + assigned_tid = attr; + break; + case Challenge: + if (conf_verbose) + log_warn("l2tp: Challenge in SCCRQ is not supported\n"); + return; + case Assigned_Connection_ID: + assigned_cid = attr; + break; + case Router_ID: + router_id = attr; + break; + case Message_Digest: + if (conf_verbose) + log_warn("l2tp: Message-Digest is not supported\n"); + return; + } + } + + if (assigned_tid) { + if (!protocol_version) { + if (conf_verbose) + log_warn("l2tp: SCCRQ: no Protocol-Version present in message\n"); + return; + } + if (protocol_version->val.uint16 != L2TP_V2_PROTOCOL_VERSION) { + if (conf_verbose) + log_warn("l2tp: protocol version %02x is not supported\n", protocol_version->val.uint16); + return; + } + if (!framing_cap) { + if (conf_verbose) + log_warn("l2tp: SCCRQ: no Framing-Capabilities present in message\n"); + return; + } + + l2tp_alloc(serv, pack, assigned_tid, framing_cap); + + } else if (assigned_cid) { + // not yet implemented + return; + } else { + if (conf_verbose) + log_warn("l2tp: SCCRQ: no Assigned-Tunnel-ID or Assigned-Connection-ID present in message\n"); + return; + } +} + +static void l2tp_recv_SCCCN(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) +{ + if (conn->state == STATE_WAIT_SCCCN) { + l2tp_send_ZLB(conn); + conn->state = STATE_WAIT_OCRQ; + } + else + log_ppp_warn("l2tp: unexpected SCCCN\n"); +} + +static void l2tp_recv_StopCCN(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) +{ + +} + +static void l2tp_recv_HELLO(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) +{ + +} + +static void l2tp_recv_OCRQ(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) +{ + struct l2tp_attr_t *attr; + struct l2tp_attr_t *assigned_sid = NULL; + + if (conn->state != STATE_WAIT_OCRQ) { + log_ppp_warn("l2tp: unexpected OCRQ\n"); + return; + } + + list_for_each_entry(attr, &pack->attrs, entry) { + switch(attr->attr->id) { + case Assigned_Session_ID: + assigned_sid = attr; + break; + case Call_Serial_Number: + case Minimum_BPS: + case Maximum_BPS: + case Bearer_Type: + case Framing_Type: + case Called_Number: + case Sub_Address: + break; + default: + if (attr->M) { + if (conf_verbose) { + log_ppp_warn("l2tp: OCRQ: unknown attribute %i\n", attr->attr->id); + l2tp_terminate(conn, 2, 8); + return; + } + } + } + } + + if (!assigned_sid) { + if (conf_verbose) + log_ppp_warn("l2tp: OCRQ: no Assigned-Session-ID attribute present in message\n"); + l2tp_terminate(conn, 2, 0); + return; + } + + l2tp_send_OCRP(conn); + + conn->peer_sid = assigned_sid->val.uint16; + + l2tp_connect(conn); +} + +static void l2tp_recv_OCCN(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) +{ + +} + +static void l2tp_recv_CDN(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) +{ + +} + +static void l2tp_recv_SLI(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) +{ + +} + +static void l2tp_ctx_recv(struct l2tp_conn_t *conn) +{ + struct l2tp_packet_t *pack; + struct l2tp_attr_t *msg_type; + + pthread_mutex_lock(&conn->lock); + if (list_empty(&conn->recv_queue)) { + pthread_mutex_unlock(&conn->lock); + return; + } + pack = list_entry(conn->recv_queue.next, typeof(*pack), entry); + list_del(&pack->entry); + pthread_mutex_unlock(&conn->lock); + + if (conf_verbose) { + log_ppp_info("recv "); + l2tp_packet_print(pack); + } + + if (ntohs(pack->hdr.Ns) == conn->Nr + 1) { + conn->Nr++; + if (!list_empty(&conn->send_queue)) { + pack = list_entry(conn->send_queue.next, typeof(*pack), entry); + list_del(&pack->entry); + l2tp_packet_free(pack); + conn->retransmit = 0; + } + if (!list_empty(&conn->send_queue)) + triton_timer_mod(&conn->timeout_timer, 0); + else if (conn->timeout_timer.tpd) + triton_timer_del(&conn->timeout_timer); + } else { + if (ntohs(pack->hdr.Ns) < conn->Nr + 1 || (ntohs(pack->hdr.Ns > 32767 && conn->Nr + 1 < 32767))) { + log_ppp_debug("duplicate packet\n"); + l2tp_send_ZLB(conn); + } else + log_ppp_debug("reordered packet\n"); + l2tp_packet_free(pack); + return; + } + + if (list_empty(&pack->attrs)) { + l2tp_packet_free(pack); + return; + } + + msg_type = list_entry(pack->attrs.next, typeof(*msg_type), entry); + + if (msg_type->attr->id != Message_Type) { + if (conf_verbose) + log_ppp_error("l2tp: first attribute is not Message-Type, dropping connection...\n"); + goto drop; + } + + switch (msg_type->val.uint16) { + case Message_Type_Start_Ctrl_Conn_Connected: + l2tp_recv_SCCCN(conn, pack); + break; + case Message_Type_Stop_Ctrl_Conn_Notify: + l2tp_recv_StopCCN(conn, pack); + break; + case Message_Type_Hello: + l2tp_recv_HELLO(conn, pack); + break; + case Message_Type_Outgoing_Call_Request: + l2tp_recv_OCRQ(conn, pack); + break; + case Message_Type_Outgoing_Call_Connected: + l2tp_recv_OCCN(conn, pack); + break; + case Message_Type_Call_Disconnect_Notify: + l2tp_recv_CDN(conn, pack); + break; + case Message_Type_Set_Link_Info: + l2tp_recv_SLI(conn, pack); + break; + case Message_Type_Start_Ctrl_Conn_Reply: + case Message_Type_Outgoing_Call_Reply: + case Message_Type_Incoming_Call_Request: + case Message_Type_Incoming_Call_Reply: + case Message_Type_Incoming_Call_Connected: + case Message_Type_WAN_Error_Notify: + if (conf_verbose) + log_warn("l2tp: unexpected Message-Type %i\n", msg_type->val.uint16); + break; + default: + if (conf_verbose) + log_warn("l2tp: unknown Message-Type %i\n", msg_type->val.uint16); + if (msg_type->M) + l2tp_terminate(conn, 2, 8); + } + + l2tp_packet_free(pack); + + return; + +drop: + l2tp_packet_free(pack); + l2tp_disconnect(conn); +} + +static int l2tp_udp_read(struct triton_md_handler_t *h) +{ + struct l2tp_serv_t *serv = container_of(h, typeof(*serv), hnd); + struct l2tp_packet_t *pack; + struct l2tp_attr_t *msg_type; + struct l2tp_conn_t *conn = NULL; + + while (1) { + pack = NULL; + + if (l2tp_recv(h->fd, &pack)) + break; + + if (!pack) + continue; + + if (pack->hdr.ver == 2 && pack->hdr.tid) { + conn = l2tp_conn_lookup(ntohs(pack->hdr.tid)); + if (!conn) { + if (conf_verbose) + log_warn("l2tp: tunnel %i not found\n", ntohs(pack->hdr.tid)); + goto skip; + } + + list_add_tail(&pack->entry, &conn->recv_queue); + triton_context_call(&conn->ctx, (triton_event_func)l2tp_ctx_recv, conn); + pthread_mutex_unlock(&conn->lock); + continue; + } + + if (list_empty(&pack->attrs)) { + if (conf_verbose) + log_warn("l2tp: to Message-Type attribute present\n"); + goto skip; + } + + msg_type = list_entry(pack->attrs.next, typeof(*msg_type), entry); + if (msg_type->attr->id != Message_Type) { + if (conf_verbose) + log_warn("l2tp: first attribute is not Message-Type\n"); + goto skip; + } + + if (msg_type->val.uint16 == Message_Type_Start_Ctrl_Conn_Request) + l2tp_recv_SCCRQ(serv, pack); + else { + if (conf_verbose) { + log_warn("recv (unexpected) "); + l2tp_packet_print(pack); + } + } +skip: + l2tp_packet_free(pack); + } + + return 0; +} + +static void l2tp_udp_close(struct triton_context_t *ctx) +{ + struct l2tp_serv_t *serv = container_of(ctx, typeof(*serv), ctx); +} + +static struct l2tp_serv_t udp_serv = +{ + .hnd.read=l2tp_udp_read, + .ctx.close=l2tp_udp_close, +}; + +/*static struct l2tp_serv_t ip_serv = +{ + .hnd.read=l2t_ip_read, + .ctx.close=l2tp_ip_close, +};*/ + +static void start_udp_server(void) +{ + struct sockaddr_in addr; + char *opt; + + udp_serv.hnd.fd = socket(PF_INET, SOCK_DGRAM, 0); + if (udp_serv.hnd.fd < 0) { + log_emerg("l2tp: socket: %s\n", strerror(errno)); + return; + } + addr.sin_family = AF_INET; + addr.sin_port = htons(L2TP_PORT); + + opt = conf_get_opt("l2tp", "bind"); + if (opt) + addr.sin_addr.s_addr = inet_addr(opt); + else + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + setsockopt(udp_serv.hnd.fd, SOL_SOCKET, SO_REUSEADDR, &udp_serv.hnd.fd, 4); + if (bind (udp_serv.hnd.fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) { + log_emerg("l2tp: failed to bind socket: %s\n", strerror(errno)); + close(udp_serv.hnd.fd); + return; + } + + if (fcntl(udp_serv.hnd.fd, F_SETFL, O_NONBLOCK)) { + log_emerg("pptp: failed to set nonblocking mode: %s\n", strerror(errno)); + close(udp_serv.hnd.fd); + return; + } + + memcpy(&udp_serv.addr, &addr, sizeof(addr)); + + triton_context_register(&udp_serv.ctx, NULL); + triton_md_register_handler(&udp_serv.ctx, &udp_serv.hnd); + triton_md_enable_handler(&udp_serv.hnd, MD_MODE_READ); + triton_context_wakeup(&udp_serv.ctx); +} + +static void __init l2tp_init(void) +{ + char *opt; + + l2tp_conn = malloc(L2TP_MAX_TID * sizeof(void *)); + memset(l2tp_conn, 0, L2TP_MAX_TID * sizeof(void *)); + + l2tp_conn_pool = mempool_create(sizeof(struct l2tp_conn_t)); + + opt = conf_get_opt("l2tp", "verbose"); + if (opt && atoi(opt) > 0) + conf_verbose = 1; + + start_udp_server(); +} + diff --git a/accel-pptpd/ctrl/l2tp/l2tp.h b/accel-pptpd/ctrl/l2tp/l2tp.h new file mode 100644 index 00000000..a99bdc35 --- /dev/null +++ b/accel-pptpd/ctrl/l2tp/l2tp.h @@ -0,0 +1,84 @@ +#ifndef __L2TP_H +#define __L2TP_H + +#include + +#include "list.h" +#include "l2tp_prot.h" + +#define ATTR_TYPE_NONE 0 +#define ATTR_TYPE_INT16 1 +#define ATTR_TYPE_INT32 2 +#define ATTR_TYPE_INT64 3 +#define ATTR_TYPE_OCTETS 4 +#define ATTR_TYPE_STRING 5 + +#define L2TP_MAX_PACKET_SIZE 65536 +#define L2TP_MAX_TID 65534 + +#define L2TP_V2_PROTOCOL_VERSION ( 1 << 8 | 0 ) + +typedef union +{ + uint32_t uint32; + int32_t int32; + uint16_t uint16; + int16_t int16; + uint64_t uint64; + uint8_t *octets; + char *string; +} l2tp_value_t; + +struct l2tp_dict_attr_t +{ + struct list_head entry; + const char *name; + int id; + int type; + int M; + int H; + struct list_head values; +}; + +struct l2tp_dict_value_t +{ + struct list_head entry; + const char *name; + l2tp_value_t val; +}; + +struct l2tp_attr_t +{ + struct list_head entry; + struct l2tp_dict_attr_t *attr; + int M:1; + int H:1; + int length; + l2tp_value_t val; +}; + +struct l2tp_packet_t +{ + struct list_head entry; + struct sockaddr_in addr; + struct l2tp_hdr_t hdr; + struct list_head attrs; +}; + +extern int conf_verbose; + +struct l2tp_dict_attr_t *l2tp_dict_find_attr_by_name(const char *name); +struct l2tp_dict_attr_t *l2tp_dict_find_attr_by_id(int id); +struct l2tp_dict_value_t *l2tp_dict_find_value(struct l2tp_dict_attr_t *attr, l2tp_value_t val); + +int l2tp_recv(int fd, struct l2tp_packet_t **); +void l2tp_packet_free(struct l2tp_packet_t *); +void l2tp_packet_print(struct l2tp_packet_t *); +struct l2tp_packet_t *l2tp_packet_alloc(int ver, int msg_type, struct sockaddr_in *addr); +int l2tp_packet_send(int sock, struct l2tp_packet_t *); +int l2tp_packet_add_int16(struct l2tp_packet_t *pack, int id, int16_t val); +int l2tp_packet_add_int32(struct l2tp_packet_t *pack, int id, int32_t val); +int l2tp_packet_add_string(struct l2tp_packet_t *pack, int id, const char *val); +int l2tp_packet_add_octets(struct l2tp_packet_t *pack, int id, const uint8_t *val, int size); + +#endif diff --git a/accel-pptpd/ctrl/l2tp/l2tp_prot.h b/accel-pptpd/ctrl/l2tp/l2tp_prot.h new file mode 100644 index 00000000..1c1d9dae --- /dev/null +++ b/accel-pptpd/ctrl/l2tp/l2tp_prot.h @@ -0,0 +1,55 @@ +#ifndef __L2TP_PROT_H +#define __L2TP_PROT_H + +#include + +#define L2TP_PORT 1701 + +struct l2tp_hdr_t +{ + uint8_t P:1; + uint8_t O:1; + uint8_t reserved2:1; + uint8_t S:1; + uint8_t reserved1:2; + uint8_t L:1; + uint8_t T:1; + uint8_t ver:4; + uint8_t reserved3:4; + uint16_t length; + union { + struct { + uint16_t tid; + uint16_t sid; + }; + uint32_t cid; + }; + uint16_t Ns; + uint16_t Nr; +} __attribute__((packed)); + +/*#define L2TP_T(hdr) (hdr->flags >> 15) +#define L2TP_L(hdr) ((hdr->flags >> 14) & 1) +#define L2TP_S(hdr) ((hdr->flags >> 10) & 1) +#define L2TP_O(hdr) ((hdr->flags >> 8) & 1) +#define L2TP_VER(hdr) (hdr->flags & 0xf)*/ + +struct l2tp_avp_t +{ + uint16_t length:10; + uint16_t reserved:4; + uint16_t H:1; + uint16_t M:1; + uint16_t vendor; + uint16_t type; + uint8_t val[0]; +} __attribute__((packed)); + +struct l2tp_avp_result_code +{ + uint16_t result_code; + uint16_t error_code; +} __attribute__((packed)); + +#endif + diff --git a/accel-pptpd/ctrl/l2tp/packet.c b/accel-pptpd/ctrl/l2tp/packet.c new file mode 100644 index 00000000..e0ff65ad --- /dev/null +++ b/accel-pptpd/ctrl/l2tp/packet.c @@ -0,0 +1,457 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "triton.h" +#include "log.h" +#include "mempool.h" +#include "memdebug.h" + +#include "l2tp.h" +#include "attr_defs.h" + +static mempool_t attr_pool; +static mempool_t pack_pool; +static mempool_t buf_pool; + +void l2tp_packet_print(struct l2tp_packet_t *pack) +{ + struct l2tp_attr_t *attr; + struct l2tp_dict_value_t *val; + + if (pack->hdr.ver == 2) + log_ppp_info("[L2TP tid=%i sid=%i Ns=%i Nr=%i", + pack->hdr.tid, pack->hdr.sid, pack->hdr.Ns, pack->hdr.Nr); + else + log_ppp_info("[L2TP cid=%u Ns=%i Nr=%i", + pack->hdr.cid, pack->hdr.Ns, pack->hdr.Nr); + + list_for_each_entry(attr, &pack->attrs, entry) { + log_ppp_info(" <%s", attr->attr->name); + val = l2tp_dict_find_value(attr->attr, attr->val); + if (val) + log_ppp_info(" %s", val->name); + else { + switch (attr->attr->type) { + case ATTR_TYPE_INT16: + log_ppp_info(" %i", attr->val.int16); + break; + case ATTR_TYPE_INT32: + log_ppp_info(" %i", attr->val.int32); + break; + case ATTR_TYPE_STRING: + log_ppp_info(" %s", attr->val.string); + break; + } + } + log_ppp_info(">"); + } + + log_ppp_info("]\n"); +} + +struct l2tp_packet_t *l2tp_packet_alloc(int ver, int msg_type, struct sockaddr_in *addr) +{ + struct l2tp_packet_t *pack = mempool_alloc(pack_pool); + if (!pack) + return NULL; + + memset(pack, 0, sizeof(*pack)); + INIT_LIST_HEAD(&pack->attrs); + pack->hdr.ver = ver; + pack->hdr.T = 1; + pack->hdr.L = 1; + pack->hdr.S = 1; + memcpy(&pack->addr, addr, sizeof(*addr)); + + if (msg_type) { + if (l2tp_packet_add_int16(pack, Message_Type, msg_type)) { + mempool_free(pack); + return NULL; + } + } + + return pack; +} + +void l2tp_packet_free(struct l2tp_packet_t *pack) +{ + struct l2tp_attr_t *attr; + + while (!list_empty(&pack->attrs)) { + attr = list_entry(pack->attrs.next, typeof(*attr), entry); + if (attr->attr->type == ATTR_TYPE_OCTETS || attr->attr->type == ATTR_TYPE_STRING) + _free(attr->val.octets); + list_del(&attr->entry); + mempool_free(attr); + } + + mempool_free(pack); +} + +int l2tp_recv(int fd, struct l2tp_packet_t **p) +{ + int n, length; + uint8_t *buf = mempool_alloc(buf_pool); + struct l2tp_hdr_t *hdr = (struct l2tp_hdr_t *)buf; + struct l2tp_avp_t *avp; + struct l2tp_dict_attr_t *da; + struct l2tp_attr_t *attr, *RV = NULL; + uint8_t *ptr = (uint8_t *)(hdr + 1); + struct l2tp_packet_t *pack; + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + + if (!buf) { + log_emerg("l2tp: out of memory\n"); + return 0; + } + + n = recvfrom(fd, buf, L2TP_MAX_PACKET_SIZE, 0, &addr, &len); + + if (n < 0) { + if (errno == EAGAIN) + return -1; + log_error("l2tp: recv: %s\n", strerror(errno)); + return 0; + } + + if (n < sizeof(*hdr)) { + if (conf_verbose) + log_warn("l2tp: short packet received (%i/%i)\n", n, sizeof(*hdr)); + goto out_err; + } + + if (n < ntohs(hdr->length)) { + if (conf_verbose) + log_warn("l2tp: short packet received (%i/%i)\n", n, ntohs(hdr->length)); + goto out_err; + } + + if (hdr->T == 0) + goto out_err_hdr; + + if (hdr->ver == 2) { + if (hdr->L == 0) { + if (conf_verbose) + log_warn("l2tp: incorrect message received (L=0)\n"); + goto out_err_hdr; + } + + if (hdr->S == 0) { + if (conf_verbose) + log_warn("l2tp: incorrect message received (S=0)\n"); + goto out_err_hdr; + } + + if (hdr->O == 1) { + if (conf_verbose) + log_warn("l2tp: incorrect message received (O=1)\n"); + goto out_err_hdr; + } + } else if (hdr->ver != 3) { + if (conf_verbose) + log_warn("l2tp: protocol version %i is not supported\n", hdr->ver); + goto out_err_hdr; + } + + pack = mempool_alloc(pack_pool); + if (!pack) { + log_emerg("l2tp: out of memory\n"); + mempool_free(buf); + return -1; + } + + memset(pack, 0, sizeof(*pack)); + INIT_LIST_HEAD(&pack->attrs); + + memcpy(&pack->addr, &addr, sizeof(addr)); + memcpy(&pack->hdr, hdr, sizeof(*hdr)); + length = ntohs(hdr->length) - sizeof(*hdr); + + while (length) { + *(uint16_t *)ptr = ntohs(*(uint16_t *)ptr); + avp = (struct l2tp_avp_t *)ptr; + + if (avp->length > length) { + if (conf_verbose) + log_warn("l2tp: incorrect avp received (exceeds message length)\n"); + goto out_err; + } + + da = l2tp_dict_find_attr_by_id(ntohs(avp->type)); + if (!da) { + if (conf_verbose) + log_warn("l2tp: unknown avp received (type=%i, M=%u)\n", ntohs(avp->type), avp->M); + if (avp->M) + goto out_err; + } else { + if (da->M != -1 && da->M != avp->M) { + if (conf_verbose) + log_warn("l2tp: incorrect avp received (type=%i, M=%i, must be %i)\n", ntohs(avp->type), avp->M, da->M); + goto out_err; + } + + if (da->H != -1 && da->H != avp->H) { + if (conf_verbose) + log_warn("l2tp: incorrect avp received (type=%i, H=%i, must be %i)\n", ntohs(avp->type), avp->H, da->H); + goto out_err; + } + + if (avp->H) { + if (!RV) { + if (conf_verbose) + log_warn("l2tp: incorrect avp received (type=%i, H=1, but Random-Vector is not received)\n", ntohs(avp->type)); + goto out_err; + } else { + if (conf_verbose) + log_warn("l2tp: hidden avp received (type=%i)\n", ntohs(avp->type)); + } + } + + attr = mempool_alloc(attr_pool); + memset(attr, 0, sizeof(*attr)); + list_add_tail(&attr->entry, &pack->attrs); + + attr->attr = da; + attr->M = avp->M; + attr->H = avp->H; + attr->length = avp->length - sizeof(*avp); + + if (attr->attr->id == Random_Vector) + RV = attr; + + switch (da->type) { + case ATTR_TYPE_INT16: + if (avp->length != sizeof(*avp) + 2) + goto out_err_len; + attr->val.uint16 = ntohs(*(uint16_t *)avp->val); + break; + case ATTR_TYPE_INT32: + if (avp->length != sizeof(*avp) + 4) + goto out_err_len; + attr->val.uint32 = ntohl(*(uint32_t *)avp->val); + break; + case ATTR_TYPE_INT64: + if (avp->length != sizeof(*avp) + 8) + goto out_err_len; + attr->val.uint64 = *(uint64_t *)avp->val; + break; + case ATTR_TYPE_OCTETS: + attr->val.octets = _malloc(attr->length); + if (!attr->val.octets) + goto out_err_mem; + memcpy(attr->val.octets, avp->val, attr->length); + break; + case ATTR_TYPE_STRING: + attr->val.string = _malloc(attr->length + 1); + if (!attr->val.string) + goto out_err_mem; + memcpy(attr->val.string, avp->val, attr->length); + attr->val.string[attr->length] = 0; + break; + } + } + + ptr += avp->length; + length -= avp->length; + } + + *p = pack; + + mempool_free(buf); + + return 0; + +out_err: + l2tp_packet_free(pack); +out_err_hdr: + mempool_free(buf); + return 0; +out_err_len: + if (conf_verbose) + log_warn("l2tp: incorrect avp received (type=%i, incorrect length %i)\n", ntohs(avp->type), avp->length); + goto out_err; +out_err_mem: + log_emerg("l2tp: out of memory\n"); + goto out_err; +} + +int l2tp_packet_send(int sock, struct l2tp_packet_t *pack) +{ + uint8_t *buf = mempool_alloc(buf_pool); + struct l2tp_avp_t *avp; + struct l2tp_attr_t *attr; + uint8_t *ptr; + int n; + int len = sizeof(pack->hdr); + + if (!buf) { + log_emerg("l2tp: out of memory\n"); + return -1; + } + + memset(buf, 0, L2TP_MAX_PACKET_SIZE); + + ptr = buf + sizeof(pack->hdr); + + list_for_each_entry(attr, &pack->attrs, entry) { + if (len + sizeof(*avp) + attr->length >= L2TP_MAX_PACKET_SIZE) { + log_error("l2tp: cann't send packet (exceeds maximum size)\n"); + mempool_free(buf); + return -1; + } + avp = (struct l2tp_avp_t *)ptr; + avp->type = htons(attr->attr->id); + avp->M = attr->M; + avp->H = attr->H; + avp->length = sizeof(*avp) + attr->length; + *(uint16_t *)ptr = htons(*(uint16_t *)ptr); + switch (attr->attr->type) { + case ATTR_TYPE_INT16: + *(int16_t *)avp->val = htons(attr->val.int16); + break; + case ATTR_TYPE_INT32: + *(int32_t *)avp->val = htonl(attr->val.int32); + break; + case ATTR_TYPE_STRING: + case ATTR_TYPE_OCTETS: + memcpy(avp->val, attr->val.string, attr->length); + break; + } + + ptr += sizeof(*avp) + attr->length; + len += sizeof(*avp) + attr->length; + } + + pack->hdr.length = htons(len); + memcpy(buf, &pack->hdr, sizeof(pack->hdr)); + + n = sendto(sock, buf, ntohs(pack->hdr.length), 0, &pack->addr, sizeof(pack->addr)); + + mempool_free(buf); + + if (n < 0) { + if (errno == EAGAIN) { + if (conf_verbose) + log_warn("l2tp: buffer overflow (packet lost)\n"); + } else { + if (conf_verbose) + log_warn("l2tp: sendto: %s\n", strerror(errno)); + return -1; + } + } + + if (n != ntohs(pack->hdr.length)) { + if (conf_verbose) + log_warn("l2tp: short write (%i/%i)\n", n, ntohs(pack->hdr.length)); + } + + return 0; +} + +static struct l2tp_attr_t *attr_alloc(int id) +{ + struct l2tp_attr_t *attr; + struct l2tp_dict_attr_t *da; + + da = l2tp_dict_find_attr_by_id(id); + if (!da) + return NULL; + + attr = mempool_alloc(attr_pool); + if (!attr) { + log_emerg("l2tp: out of memory\n"); + return NULL; + } + + memset(attr, 0, sizeof(*attr)); + + attr->attr = da; + + if (da->M != -1) + attr->M = da->M; + if (da->H != -1) + attr->H = da->H; + + return attr; +} + +int l2tp_packet_add_int16(struct l2tp_packet_t *pack, int id, int16_t val) +{ + struct l2tp_attr_t *attr = attr_alloc(id); + + if (!attr) + return -1; + + attr->length = 2; + attr->val.int16 = val; + list_add_tail(&attr->entry, &pack->attrs); + + return 0; +} +int l2tp_packet_add_int32(struct l2tp_packet_t *pack, int id, int32_t val) +{ + struct l2tp_attr_t *attr = attr_alloc(id); + + if (!attr) + return -1; + + attr->length = 4; + attr->val.int32 = val; + list_add_tail(&attr->entry, &pack->attrs); + + return 0; +} +int l2tp_packet_add_string(struct l2tp_packet_t *pack, int id, const char *val) +{ + struct l2tp_attr_t *attr = attr_alloc(id); + + if (!attr) + return -1; + + attr->length = strlen(val); + attr->val.string = _strdup(val); + if (!attr->val.string) { + log_emerg("l2tp: out of memory\n"); + mempool_free(attr); + return -1; + } + memcpy(attr->val.string, val, attr->length); + list_add_tail(&attr->entry, &pack->attrs); + + return 0; +} + +int l2tp_packet_add_octets(struct l2tp_packet_t *pack, int id, const uint8_t *val, int size) +{ + struct l2tp_attr_t *attr = attr_alloc(id); + + if (!attr) + return -1; + + attr->length = size; + attr->val.octets = _malloc(size); + if (!attr->val.string) { + log_emerg("l2tp: out of memory\n"); + mempool_free(attr); + return -1; + } + memcpy(attr->val.octets, val, attr->length); + list_add_tail(&attr->entry, &pack->attrs); + + return 0; +} + +static void __init init(void) +{ + attr_pool = mempool_create(sizeof(struct l2tp_attr_t)); + pack_pool = mempool_create(sizeof(struct l2tp_packet_t)); + buf_pool = mempool_create(L2TP_MAX_PACKET_SIZE); +} + diff --git a/accel-pptpd/ctrl/pppoe.c b/accel-pptpd/ctrl/pppoe.c deleted file mode 100644 index d59a3174..00000000 --- a/accel-pptpd/ctrl/pppoe.c +++ /dev/null @@ -1,882 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "events.h" -#include "triton.h" -#include "log.h" -#include "ppp.h" -#include "mempool.h" - -#include "pppoe.h" - -#include "memdebug.h" - - -struct pppoe_serv_t -{ - struct triton_context_t ctx; - struct triton_md_handler_t hnd; - uint8_t hwaddr[ETH_ALEN]; - const char *ifname; - - pthread_mutex_t lock; - struct pppoe_conn_t *conn[MAX_SID]; - uint16_t sid; -}; - -struct pppoe_conn_t -{ - struct triton_context_t ctx; - struct pppoe_serv_t *serv; - int disc_sock; - uint16_t sid; - uint8_t addr[ETH_ALEN]; - int ppp_started:1; - - struct pppoe_tag *relay_sid; - struct pppoe_tag *host_uniq; - - struct ppp_ctrl_t ctrl; - struct ppp_t ppp; -}; - -static int conf_verbose = 0; -static const char *conf_service_name = ""; -static const char *conf_ac_name = "accel-pptp"; - -static mempool_t conn_pool; - -#define SECRET_SIZE 16 -static uint8_t *secret; - -static uint8_t bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - -static void pppoe_send_PADT(struct pppoe_conn_t *conn); - -static void disconnect(struct pppoe_conn_t *conn) -{ - if (conn->ppp_started) { - conn->ppp_started = 0; - ppp_terminate(&conn->ppp, 1); - } - - pppoe_send_PADT(conn); - - close(conn->disc_sock); - - triton_event_fire(EV_CTRL_FINISHED, &conn->ppp); - - if (conf_verbose) - log_ppp_info("disconnected\n"); - - pthread_mutex_lock(&conn->serv->lock); - conn->serv->conn[conn->sid] = NULL; - pthread_mutex_unlock(&conn->serv->lock); - - _free(conn->ctrl.calling_station_id); - _free(conn->ctrl.called_station_id); - if (conn->host_uniq) - _free(conn->host_uniq); - if (conn->relay_sid) - _free(conn->relay_sid); - - triton_context_unregister(&conn->ctx); - - mempool_free(conn); -} - -static void ppp_started(struct ppp_t *ppp) -{ - log_ppp_debug("pppoe: ppp started\n"); -} - -static void ppp_finished(struct ppp_t *ppp) -{ - struct pppoe_conn_t *conn = container_of(ppp, typeof(*conn), ppp); - - log_ppp_debug("pppoe: ppp finished\n"); - - if (conn->ppp_started) { - conn->ppp_started = 0; - disconnect(conn); - } -} - -static void pppoe_conn_close(struct triton_context_t *ctx) -{ - struct pppoe_conn_t *conn = container_of(ctx, typeof(*conn), ctx); - - if (conn->ppp_started) - ppp_terminate(&conn->ppp, 0); - else - disconnect(conn); -} - -static struct pppoe_conn_t *allocate_channel(struct pppoe_serv_t *serv, const uint8_t *addr, const struct pppoe_tag *host_uniq, const struct pppoe_tag *relay_sid) -{ - struct pppoe_conn_t *conn; - int sid; - - conn = mempool_alloc(conn_pool); - if (!conn) { - log_emerg("pppoe: out of memory\n"); - return NULL; - } - - memset(conn, 0, sizeof(*conn)); - - pthread_mutex_lock(&serv->lock); - for (sid = serv->sid + 1; sid != serv->sid; sid++) { - if (sid == MAX_SID) - sid = 1; - if (!serv->conn[sid]) { - conn->sid = sid; - serv->sid = sid; - serv->conn[sid] = conn; - break; - } - } - pthread_mutex_unlock(&serv->lock); - - if (!conn->sid) { - log_warn("pppoe: no free sid available\n"); - mempool_free(conn); - return NULL; - } - - conn->serv = serv; - memcpy(conn->addr, addr, ETH_ALEN); - - if (host_uniq) { - conn->host_uniq = _malloc(sizeof(*host_uniq) + ntohs(host_uniq->tag_len)); - memcpy(conn->host_uniq, host_uniq, sizeof(*host_uniq) + ntohs(host_uniq->tag_len)); - } - - if (relay_sid) { - conn->relay_sid = _malloc(sizeof(*relay_sid) + ntohs(relay_sid->tag_len)); - memcpy(conn->relay_sid, relay_sid, sizeof(*relay_sid) + ntohs(relay_sid->tag_len)); - } - - conn->ctx.close = pppoe_conn_close; - conn->ctrl.ctx = &conn->ctx; - conn->ctrl.started = ppp_started; - conn->ctrl.finished = ppp_finished; - conn->ctrl.max_mtu = MAX_PPPOE_MTU; - conn->ctrl.name = "pppoe"; - - conn->ctrl.calling_station_id = _malloc(19); - conn->ctrl.called_station_id = _malloc(19); - sprintf(conn->ctrl.calling_station_id, "%02x:%02x:%02x:%02x:%02x:%02x", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); - sprintf(conn->ctrl.called_station_id, "%02x:%02x:%02x:%02x:%02x:%02x", - serv->hwaddr[0], serv->hwaddr[1], serv->hwaddr[2], serv->hwaddr[3], serv->hwaddr[4], serv->hwaddr[5]); - - ppp_init(&conn->ppp); - - conn->ppp.ctrl = &conn->ctrl; - conn->ppp.chan_name = conn->ctrl.calling_station_id; - - triton_context_register(&conn->ctx, &conn->ppp); - triton_context_wakeup(&conn->ctx); - - triton_event_fire(EV_CTRL_STARTING, &conn->ppp); - triton_event_fire(EV_CTRL_STARTED, &conn->ppp); - - conn->disc_sock = dup(serv->hnd.fd); - - return conn; -} - -static int connect_channel(struct pppoe_conn_t *conn) -{ - int sock; - struct sockaddr_pppox sp; - - sock = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_OE); - if (!sock) { - log_error("pppoe: socket(PPPOX): %s\n", strerror(errno)); - return -1; - } - - memset(&sp, 0, sizeof(sp)); - - sp.sa_family = AF_PPPOX; - sp.sa_protocol = PX_PROTO_OE; - sp.sa_addr.pppoe.sid = htons(conn->sid); - strcpy(sp.sa_addr.pppoe.dev, conn->serv->ifname); - memcpy(sp.sa_addr.pppoe.remote, conn->addr, ETH_ALEN); - - if (connect(sock, (struct sockaddr *)&sp, sizeof(sp))) { - log_error("pppoe: connect: %s\n", strerror(errno)); - close(sock); - return -1; - } - - conn->ppp.fd = sock; - - if (establish_ppp(&conn->ppp)) { - close(sock); - return -1; - } - - return 0; -} - -static void print_tag_string(struct pppoe_tag *tag) -{ - int i; - - for (i = 0; i < ntohs(tag->tag_len); i++) - log_info("%c", tag->tag_data[i]); -} - -static void print_tag_octets(struct pppoe_tag *tag) -{ - int i; - - for (i = 0; i < ntohs(tag->tag_len); i++) - log_info("%02x", (uint8_t)tag->tag_data[i]); -} - -static void print_packet(uint8_t *pack) -{ - struct ethhdr *ethhdr = (struct ethhdr *)pack; - struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); - struct pppoe_tag *tag; - int n; - - log_info("[PPPoE "); - - switch (hdr->code) { - case CODE_PADI: - log_info("PADI"); - break; - case CODE_PADO: - log_info("PADO"); - break; - case CODE_PADR: - log_info("PADR"); - break; - case CODE_PADS: - log_info("PADS"); - break; - case CODE_PADT: - log_info("PADT"); - break; - } - - log_info(" %02x:%02x:%02x:%02x:%02x:%02x => %02x:%02x:%02x:%02x:%02x:%02x", - ethhdr->h_source[0], ethhdr->h_source[1], ethhdr->h_source[2], ethhdr->h_source[3], ethhdr->h_source[4], ethhdr->h_source[5], - ethhdr->h_dest[0], ethhdr->h_dest[1], ethhdr->h_dest[2], ethhdr->h_dest[3], ethhdr->h_dest[4], ethhdr->h_dest[5]); - - log_info(" sid=%04x", ntohs(hdr->sid)); - - for (n = 0; n < ntohs(hdr->length); n += sizeof(*tag) + ntohs(tag->tag_len)) { - tag = (struct pppoe_tag *)(pack + ETH_HLEN + sizeof(*hdr) + n); - switch (ntohs(tag->tag_type)) { - case TAG_END_OF_LIST: - log_info(" "); - break; - case TAG_SERVICE_NAME: - log_info(" "); - break; - case TAG_AC_NAME: - log_info(" "); - break; - case TAG_HOST_UNIQ: - log_info(" "); - break; - case TAG_AC_COOKIE: - log_info(" "); - break; - case TAG_VENDOR_SPECIFIC: - log_info(" "); - break; - case TAG_RELAY_SESSION_ID: - log_info(" "); - break; - case TAG_SERVICE_NAME_ERROR: - log_info(" "); - break; - case TAG_AC_SYSTEM_ERROR: - log_info(" "); - break; - case TAG_GENERIC_ERROR: - log_info(" "); - break; - default: - log_info(" ", ntohs(tag->tag_type)); - break; - } - } - - log_info("]\n"); -} - -static void generate_cookie(const uint8_t *src, const uint8_t *dst, uint8_t *cookie) -{ - MD5_CTX ctx; - - MD5_Init(&ctx); - MD5_Update(&ctx, secret, SECRET_SIZE); - MD5_Update(&ctx, src, ETH_ALEN); - MD5_Update(&ctx, dst, ETH_ALEN); - MD5_Update(&ctx, conf_ac_name, strlen(conf_ac_name)); - MD5_Update(&ctx, secret, SECRET_SIZE); - MD5_Final(cookie, &ctx); -} - -static void setup_header(uint8_t *pack, const uint8_t *src, const uint8_t *dst, int code, uint16_t sid) -{ - struct ethhdr *ethhdr = (struct ethhdr *)pack; - struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); - - memcpy(ethhdr->h_source, src, ETH_ALEN); - memcpy(ethhdr->h_dest, dst, ETH_ALEN); - ethhdr->h_proto = htons(ETH_P_PPP_DISC); - - hdr->ver = 1; - hdr->type = 1; - hdr->code = code; - hdr->sid = htons(sid); - hdr->length = 0; -} - -static void add_tag(uint8_t *pack, int type, const uint8_t *data, int len) -{ - struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); - struct pppoe_tag *tag = (struct pppoe_tag *)(pack + ETH_HLEN + sizeof(*hdr) + ntohs(hdr->length)); - - tag->tag_type = htons(type); - tag->tag_len = htons(len); - memcpy(tag->tag_data, data, len); - - hdr->length = htons(ntohs(hdr->length) + sizeof(*tag) + len); -} - -static void add_tag2(uint8_t *pack, const struct pppoe_tag *t) -{ - struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); - struct pppoe_tag *tag = (struct pppoe_tag *)(pack + ETH_HLEN + sizeof(*hdr) + ntohs(hdr->length)); - - memcpy(tag, t, sizeof(*t) + ntohs(t->tag_len)); - - hdr->length = htons(ntohs(hdr->length) + sizeof(*tag) + ntohs(t->tag_len)); -} - -static void pppoe_send(int fd, const uint8_t *pack) -{ - struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); - int n, s; - - s = ETH_HLEN + sizeof(*hdr) + ntohs(hdr->length); - n = write(fd, pack, s); - if (n < 0 ) - log_error("pppoe: write: %s\n", strerror(errno)); - else if (n != s) { - log_warn("pppoe: short write %i/%i\n", n,s); - } -} - -static void pppoe_send_PADO(struct pppoe_serv_t *serv, const uint8_t *addr, const struct pppoe_tag *host_uniq, const struct pppoe_tag *relay_sid) -{ - uint8_t pack[ETHER_MAX_LEN]; - uint8_t cookie[MD5_DIGEST_LENGTH]; - - setup_header(pack, serv->hwaddr, addr, CODE_PADO, 0); - - add_tag(pack, TAG_AC_NAME, (uint8_t *)conf_ac_name, strlen(conf_ac_name)); - add_tag(pack, TAG_SERVICE_NAME, (uint8_t *)conf_service_name, strlen(conf_service_name)); - - generate_cookie(serv->hwaddr, addr, cookie); - add_tag(pack, TAG_AC_COOKIE, cookie, MD5_DIGEST_LENGTH); - - if (host_uniq) - add_tag2(pack, host_uniq); - - if (relay_sid) - add_tag2(pack, relay_sid); - - if (conf_verbose) { - log_info("send "); - print_packet(pack); - } - - pppoe_send(serv->hnd.fd, pack); -} - -static void pppoe_send_err(struct pppoe_serv_t *serv, const uint8_t *addr, const struct pppoe_tag *host_uniq, const struct pppoe_tag *relay_sid, int code, int tag_type) -{ - uint8_t pack[ETHER_MAX_LEN]; - - setup_header(pack, serv->hwaddr, addr, code, 0); - - add_tag(pack, TAG_AC_NAME, (uint8_t *)conf_ac_name, strlen(conf_ac_name)); - add_tag(pack, tag_type, NULL, 0); - - if (host_uniq) - add_tag2(pack, host_uniq); - - if (relay_sid) - add_tag2(pack, relay_sid); - - if (conf_verbose) { - log_info("send "); - print_packet(pack); - } - - pppoe_send(serv->hnd.fd, pack); -} - -static void pppoe_send_PADS(struct pppoe_conn_t *conn) -{ - uint8_t pack[ETHER_MAX_LEN]; - - setup_header(pack, conn->serv->hwaddr, conn->addr, CODE_PADS, conn->sid); - - add_tag(pack, TAG_AC_NAME, (uint8_t *)conf_ac_name, strlen(conf_ac_name)); - add_tag(pack, TAG_SERVICE_NAME, (uint8_t *)conf_service_name, strlen(conf_service_name)); - - if (conn->host_uniq) - add_tag2(pack, conn->host_uniq); - - if (conn->relay_sid) - add_tag2(pack, conn->relay_sid); - - if (conf_verbose) { - log_info("send "); - print_packet(pack); - } - - pppoe_send(conn->disc_sock, pack); -} - -static void pppoe_send_PADT(struct pppoe_conn_t *conn) -{ - uint8_t pack[ETHER_MAX_LEN]; - - setup_header(pack, conn->serv->hwaddr, conn->addr, CODE_PADT, conn->sid); - - add_tag(pack, TAG_AC_NAME, (uint8_t *)conf_ac_name, strlen(conf_ac_name)); - add_tag(pack, TAG_SERVICE_NAME, (uint8_t *)conf_service_name, strlen(conf_service_name)); - - if (conn->host_uniq) - add_tag2(pack, conn->host_uniq); - - if (conn->relay_sid) - add_tag2(pack, conn->relay_sid); - - if (conf_verbose) { - log_info("send "); - print_packet(pack); - } - - pppoe_send(conn->disc_sock, pack); -} - -static void pppoe_recv_PADI(struct pppoe_serv_t *serv, uint8_t *pack, int size) -{ - struct ethhdr *ethhdr = (struct ethhdr *)pack; - struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); - struct pppoe_tag *tag; - struct pppoe_tag *host_uniq_tag = NULL; - struct pppoe_tag *relay_sid_tag = NULL; - int n, service_match = 0; - - if (hdr->sid) { - log_warn("pppoe: discaring PADI packet (sid is not zero)\n"); - return; - } - - if (conf_verbose) { - log_info("recv "); - print_packet(pack); - } - - for (n = 0; n < ntohs(hdr->length); n += sizeof(*tag) + ntohs(tag->tag_len)) { - tag = (struct pppoe_tag *)(pack + ETH_HLEN + sizeof(*hdr) + n); - switch (ntohs(tag->tag_type)) { - case TAG_END_OF_LIST: - break; - case TAG_SERVICE_NAME: - if (tag->tag_len == 0) - service_match = 1; - else if (conf_service_name) { - if (ntohs(tag->tag_len) != strlen(conf_service_name)) - break; - if (memcmp(tag->tag_data, conf_service_name, ntohs(tag->tag_len))) - break; - service_match = 1; - } - break; - case TAG_HOST_UNIQ: - host_uniq_tag = tag; - break; - case TAG_RELAY_SESSION_ID: - relay_sid_tag = tag; - break; - } - } - - if (!service_match) { - if (conf_verbose) - log_warn("pppoe: discarding PADI packet (Service-Name mismatch)\n"); - return; - } - - pppoe_send_PADO(serv, ethhdr->h_source, host_uniq_tag, relay_sid_tag); -} - -static void pppoe_recv_PADR(struct pppoe_serv_t *serv, uint8_t *pack, int size) -{ - struct ethhdr *ethhdr = (struct ethhdr *)pack; - struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); - struct pppoe_tag *tag; - struct pppoe_tag *host_uniq_tag = NULL; - struct pppoe_tag *relay_sid_tag = NULL; - struct pppoe_tag *ac_cookie_tag = NULL; - uint8_t cookie[MD5_DIGEST_LENGTH]; - int n, service_match = 0; - struct pppoe_conn_t *conn; - - if (!memcmp(ethhdr->h_dest, bc_addr, ETH_ALEN)) { - if (conf_verbose) - log_warn("pppoe: discard PADR (destination address is broadcast)\n"); - return; - } - - if (hdr->sid) { - if (conf_verbose) - log_warn("pppoe: discaring PADR packet (sid is not zero)\n"); - return; - } - - if (conf_verbose) { - log_info("recv "); - print_packet(pack); - } - - for (n = 0; n < ntohs(hdr->length); n += sizeof(*tag) + ntohs(tag->tag_len)) { - tag = (struct pppoe_tag *)(pack + ETH_HLEN + sizeof(*hdr) + n); - switch (ntohs(tag->tag_type)) { - case TAG_END_OF_LIST: - break; - case TAG_SERVICE_NAME: - if (tag->tag_len == 0) - service_match = 1; - else if (conf_service_name) { - if (ntohs(tag->tag_len) != strlen(conf_service_name)) - break; - if (memcmp(tag->tag_data, conf_service_name, ntohs(tag->tag_len))) - break; - service_match = 1; - } - break; - case TAG_HOST_UNIQ: - host_uniq_tag = tag; - break; - case TAG_AC_COOKIE: - ac_cookie_tag = tag; - break; - case TAG_RELAY_SESSION_ID: - relay_sid_tag = tag; - break; - } - } - - if (!ac_cookie_tag) { - if (conf_verbose) - log_warn("pppoe: discard PADR packet (no AC-Cookie tag present)\n"); - return; - } - - if (ntohs(ac_cookie_tag->tag_len) != MD5_DIGEST_LENGTH) { - if (conf_verbose) - log_warn("pppoe: discard PADR packet (incorrect AC-Cookie tag length)\n"); - return; - } - - generate_cookie(serv->hwaddr, ethhdr->h_source, cookie); - - if (memcmp(cookie, ac_cookie_tag->tag_data, MD5_DIGEST_LENGTH)) { - if (conf_verbose) - log_warn("pppoe: discard PADR packet (incorrect AC-Cookie)\n"); - return; - } - - if (!service_match) { - if (conf_verbose) - log_warn("pppoe: Service-Name mismatch\n"); - pppoe_send_err(serv, ethhdr->h_source, host_uniq_tag, relay_sid_tag, CODE_PADS, TAG_SERVICE_NAME_ERROR); - return; - } - - conn = allocate_channel(serv, ethhdr->h_source, host_uniq_tag, relay_sid_tag); - if (!conn) - pppoe_send_err(serv, ethhdr->h_source, host_uniq_tag, relay_sid_tag, CODE_PADS, TAG_AC_SYSTEM_ERROR); - else { - pppoe_send_PADS(conn); - if (connect_channel(conn)) - disconnect(conn); - else - conn->ppp_started = 1; - } -} - -static void pppoe_recv_PADT(struct pppoe_serv_t *serv, uint8_t *pack) -{ - struct ethhdr *ethhdr = (struct ethhdr *)pack; - struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); - struct pppoe_conn_t *conn; - - if (!memcmp(ethhdr->h_dest, bc_addr, ETH_ALEN)) { - if (conf_verbose) - log_warn("pppoe: discard PADT (destination address is broadcast)\n"); - return; - } - - if (conf_verbose) { - log_info("recv "); - print_packet(pack); - } - - pthread_mutex_lock(&serv->lock); - conn = serv->conn[ntohs(hdr->sid)]; - if (conn && !memcmp(conn->addr, ethhdr->h_source, ETH_ALEN)) - triton_context_call(&conn->ctx, (void (*)(void *))disconnect, conn); - pthread_mutex_unlock(&serv->lock); -} - -static int pppoe_serv_read(struct triton_md_handler_t *h) -{ - struct pppoe_serv_t *serv = container_of(h, typeof(*serv), hnd); - uint8_t pack[ETHER_MAX_LEN]; - struct ethhdr *ethhdr = (struct ethhdr *)pack; - struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); - int n; - - n = read(h->fd, pack, sizeof(pack)); - if (n < 0) { - log_error("pppoe: read: %s\n", strerror(errno)); - return 0; - } - - if (n < ETH_HLEN + sizeof(*hdr)) { - if (conf_verbose) - log_warn("pppoe: short packet received (%i)\n", n); - return 0; - } - - if (memcmp(ethhdr->h_dest, bc_addr, ETH_ALEN) && memcmp(ethhdr->h_dest, serv->hwaddr, ETH_ALEN)) - return 0; - - if (!memcmp(ethhdr->h_source, bc_addr, ETH_ALEN)) { - if (conf_verbose) - log_warn("pppoe: discarding packet (host address is broadcast)\n"); - return 0; - } - - if ((ethhdr->h_source[0] & 1) != 0) { - if (conf_verbose) - log_warn("pppoe: discarding packet (host address is not unicast)\n"); - return 0; - } - - if (n < ETH_HLEN + sizeof(*hdr) + ntohs(hdr->length)) { - if (conf_verbose) - log_warn("pppoe: short packet received\n"); - return 0; - } - - if (hdr->ver != 1) { - if (conf_verbose) - log_warn("pppoe: discarding packet (unsupported version %i)\n", hdr->ver); - return 0; - } - - if (hdr->type != 1) { - if (conf_verbose) - log_warn("pppoe: discarding packet (unsupported type %i)\n", hdr->type); - } - - switch (hdr->code) { - case CODE_PADI: - pppoe_recv_PADI(serv, pack, n); - break; - case CODE_PADR: - pppoe_recv_PADR(serv, pack, n); - break; - case CODE_PADT: - pppoe_recv_PADT(serv, pack); - break; - } - - return 0; -} - -static void pppoe_serv_close(struct triton_context_t *ctx) -{ - struct pppoe_serv_t *serv = container_of(ctx, typeof(*serv), ctx); - - triton_md_unregister_handler(&serv->hnd); - close(serv->hnd.fd); - triton_context_unregister(&serv->ctx); -} - -static void pppoe_start_server(const char *ifname) -{ - struct pppoe_serv_t *serv = _malloc(sizeof(*serv)); - int sock; - int opt = 1; - struct ifreq ifr; - struct sockaddr_ll sa; - - memset(serv, 0, sizeof(*serv)); - - sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PPP_DISC)); - if (sock < 0) { - log_emerg("pppoe: socket: %s\n", strerror(errno)); - _free(serv); - return; - } - - if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt))) { - log_emerg("pppoe: setsockopt(SO_BROADCAST): %s\n", strerror(errno)); - goto out_err; - } - - strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); - if (ioctl(sock, SIOCGIFHWADDR, &ifr)) { - log_emerg("pppoe: ioctl(SIOCGIFHWADDR): %s\n", strerror(errno)); - goto out_err; - } - -#ifdef ARPHDR_ETHER - if (ifr.ifr_hwaddr.sa_family != ARPHDR_ETHER) { - log_emerg("pppoe: interface %s is not ethernet\n", ifname); - goto out_err; - } -#endif - - if ((ifr.ifr_hwaddr.sa_data[0] & 1) != 0) { - log_emerg("pppoe: interface %s has not unicast address\n", ifname); - goto out_err; - } - - memcpy(serv->hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); - - if (ioctl(sock, SIOCGIFMTU, &ifr)) { - log_emerg("pppoe: ioctl(SIOCGIFMTU): %s\n", strerror(errno)); - goto out_err; - } - - if (ifr.ifr_mtu < ETH_DATA_LEN) - log_emerg("pppoe: interface %s has MTU of %i, should be %i\n", ifname, ifr.ifr_mtu, ETH_DATA_LEN); - - if (ioctl(sock, SIOCGIFINDEX, &ifr)) { - log_emerg("pppoe: ioctl(SIOCGIFINDEX): %s\n", strerror(errno)); - goto out_err; - } - - memset(&sa, 0, sizeof(sa)); - sa.sll_family = AF_PACKET; - sa.sll_protocol = htons(ETH_P_PPP_DISC); - sa.sll_ifindex = ifr.ifr_ifindex; - - if (bind(sock, (struct sockaddr *)&sa, sizeof(sa))) { - log_emerg("pppoe: bind: %s\n", strerror(errno)); - goto out_err; - } - - serv->ctx.close = pppoe_serv_close; - serv->hnd.fd = sock; - serv->hnd.read = pppoe_serv_read; - serv->ifname = ifname; - pthread_mutex_init(&serv->lock, NULL); - - 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); - - return; - -out_err: - close(sock); - _free(serv); -} - -static int init_secret(void) -{ - int fd; - - secret = malloc(SECRET_SIZE); - - fd = open("/dev/urandom", O_RDONLY); - if (fd < 0) { - log_emerg("pppoe: cann't open /dev/urandom: %s\n", strerror(errno)); - return -1; - } - - if (read(fd, secret, SECRET_SIZE) < 0) { - log_emerg("pppoe: faild to read /dev/urandom\n", strerror(errno)); - close(fd); - return -1; - } - - close(fd); - - return 0; -} - -static void __init pppoe_init(void) -{ - struct conf_sect_t *s = conf_get_section("pppoe"); - struct conf_option_t *opt; - - conn_pool = mempool_create(sizeof(struct pppoe_conn_t)); - - if (init_secret()) - _exit(EXIT_FAILURE); - - if (!s) { - log_emerg("pppoe: no configuration, disabled...\n"); - return; - } - - list_for_each_entry(opt, &s->items, entry) { - if (!strcmp(opt->name, "interface")) - pppoe_start_server(opt->val); - else if (!strcmp(opt->name, "verbose")) { - if (atoi(opt->val) > 0) - conf_verbose = 1; - } else if (!strcmp(opt->name, "ac-name") || !strcmp(opt->name, "AC-Name")) - conf_ac_name = opt->val; - else if (!strcmp(opt->name, "service-name") || !strcmp(opt->name, "Service-Name")) - conf_service_name = opt->val; - } -} - diff --git a/accel-pptpd/ctrl/pppoe.h b/accel-pptpd/ctrl/pppoe.h deleted file mode 100644 index 05061083..00000000 --- a/accel-pptpd/ctrl/pppoe.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef __PPPOE_H -#define __PPPOE_H - -#include -#include - -/* PPPoE codes */ -#define CODE_PADI 0x09 -#define CODE_PADO 0x07 -#define CODE_PADR 0x19 -#define CODE_PADS 0x65 -#define CODE_PADT 0xA7 -#define CODE_SESS 0x00 - -/* PPPoE Tags */ -#define TAG_END_OF_LIST 0x0000 -#define TAG_SERVICE_NAME 0x0101 -#define TAG_AC_NAME 0x0102 -#define TAG_HOST_UNIQ 0x0103 -#define TAG_AC_COOKIE 0x0104 -#define TAG_VENDOR_SPECIFIC 0x0105 -#define TAG_RELAY_SESSION_ID 0x0110 -#define TAG_SERVICE_NAME_ERROR 0x0201 -#define TAG_AC_SYSTEM_ERROR 0x0202 -#define TAG_GENERIC_ERROR 0x0203 - -/* Discovery phase states */ -#define STATE_SENT_PADI 0 -#define STATE_RECEIVED_PADO 1 -#define STATE_SENT_PADR 2 -#define STATE_SESSION 3 -#define STATE_TERMINATED 4 - -/* Header size of a PPPoE packet */ -#define PPPOE_OVERHEAD 6 /* type, code, session, length */ -#define HDR_SIZE (sizeof(struct ethhdr) + PPPOE_OVERHEAD) -#define MAX_PPPOE_PAYLOAD (ETH_DATA_LEN - PPPOE_OVERHEAD) -#define MAX_PPPOE_MTU (MAX_PPPOE_PAYLOAD - 2) - -#define MAX_SID 65534 - -struct pppoe_tag_t -{ - struct list_head entry; - int type; - int len; -}; - -struct pppoe_packet_t -{ - uint8_t src[ETH_ALEN]; - uint8_t dst[ETH_ALEN]; - int code; - uint16_t sid; - struct list_head tags; -}; - -#endif - diff --git a/accel-pptpd/ctrl/pppoe/CMakeLists.txt b/accel-pptpd/ctrl/pppoe/CMakeLists.txt new file mode 100644 index 00000000..dd0f9cd5 --- /dev/null +++ b/accel-pptpd/ctrl/pppoe/CMakeLists.txt @@ -0,0 +1,5 @@ +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +ADD_LIBRARY(pppoe SHARED pppoe.c) + +INSTALL(TARGETS pppoe LIBRARY DESTINATION usr/lib/accel-pptp) diff --git a/accel-pptpd/ctrl/pppoe/pppoe.c b/accel-pptpd/ctrl/pppoe/pppoe.c new file mode 100644 index 00000000..30769b53 --- /dev/null +++ b/accel-pptpd/ctrl/pppoe/pppoe.c @@ -0,0 +1,890 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "events.h" +#include "triton.h" +#include "log.h" +#include "ppp.h" +#include "mempool.h" + +#include "pppoe.h" + +#include "memdebug.h" + + +struct pppoe_serv_t +{ + struct triton_context_t ctx; + struct triton_md_handler_t hnd; + uint8_t hwaddr[ETH_ALEN]; + const char *ifname; + + pthread_mutex_t lock; + struct pppoe_conn_t *conn[MAX_SID]; + uint16_t sid; +}; + +struct pppoe_conn_t +{ + struct triton_context_t ctx; + struct pppoe_serv_t *serv; + int disc_sock; + uint16_t sid; + uint8_t addr[ETH_ALEN]; + int ppp_started:1; + + struct pppoe_tag *relay_sid; + struct pppoe_tag *host_uniq; + + struct ppp_ctrl_t ctrl; + struct ppp_t ppp; +}; + +static int conf_verbose = 0; +static const char *conf_service_name = ""; +static const char *conf_ac_name = "accel-pptp"; + +static mempool_t conn_pool; + +#define SECRET_SIZE 16 +static uint8_t *secret; + +static uint8_t bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + +static void pppoe_send_PADT(struct pppoe_conn_t *conn); + +static void disconnect(struct pppoe_conn_t *conn) +{ + if (conn->ppp_started) { + conn->ppp_started = 0; + ppp_terminate(&conn->ppp, 1); + } + + pppoe_send_PADT(conn); + + close(conn->disc_sock); + + triton_event_fire(EV_CTRL_FINISHED, &conn->ppp); + + if (conf_verbose) + log_ppp_info("disconnected\n"); + + pthread_mutex_lock(&conn->serv->lock); + conn->serv->conn[conn->sid] = NULL; + pthread_mutex_unlock(&conn->serv->lock); + + _free(conn->ctrl.calling_station_id); + _free(conn->ctrl.called_station_id); + if (conn->host_uniq) + _free(conn->host_uniq); + if (conn->relay_sid) + _free(conn->relay_sid); + + triton_context_unregister(&conn->ctx); + + mempool_free(conn); +} + +static void ppp_started(struct ppp_t *ppp) +{ + log_ppp_debug("pppoe: ppp started\n"); +} + +static void ppp_finished(struct ppp_t *ppp) +{ + struct pppoe_conn_t *conn = container_of(ppp, typeof(*conn), ppp); + + log_ppp_debug("pppoe: ppp finished\n"); + + if (conn->ppp_started) { + conn->ppp_started = 0; + disconnect(conn); + } +} + +static void pppoe_conn_close(struct triton_context_t *ctx) +{ + struct pppoe_conn_t *conn = container_of(ctx, typeof(*conn), ctx); + + if (conn->ppp_started) + ppp_terminate(&conn->ppp, 0); + else + disconnect(conn); +} + +static struct pppoe_conn_t *allocate_channel(struct pppoe_serv_t *serv, const uint8_t *addr, const struct pppoe_tag *host_uniq, const struct pppoe_tag *relay_sid) +{ + struct pppoe_conn_t *conn; + int sid; + + conn = mempool_alloc(conn_pool); + if (!conn) { + log_emerg("pppoe: out of memory\n"); + return NULL; + } + + memset(conn, 0, sizeof(*conn)); + + pthread_mutex_lock(&serv->lock); + for (sid = serv->sid + 1; sid != serv->sid; sid++) { + if (sid == MAX_SID) + sid = 1; + if (!serv->conn[sid]) { + conn->sid = sid; + serv->sid = sid; + serv->conn[sid] = conn; + break; + } + } + pthread_mutex_unlock(&serv->lock); + + if (!conn->sid) { + log_warn("pppoe: no free sid available\n"); + mempool_free(conn); + return NULL; + } + + conn->serv = serv; + memcpy(conn->addr, addr, ETH_ALEN); + + if (host_uniq) { + conn->host_uniq = _malloc(sizeof(*host_uniq) + ntohs(host_uniq->tag_len)); + memcpy(conn->host_uniq, host_uniq, sizeof(*host_uniq) + ntohs(host_uniq->tag_len)); + } + + if (relay_sid) { + conn->relay_sid = _malloc(sizeof(*relay_sid) + ntohs(relay_sid->tag_len)); + memcpy(conn->relay_sid, relay_sid, sizeof(*relay_sid) + ntohs(relay_sid->tag_len)); + } + + conn->ctx.close = pppoe_conn_close; + conn->ctrl.ctx = &conn->ctx; + conn->ctrl.started = ppp_started; + conn->ctrl.finished = ppp_finished; + conn->ctrl.max_mtu = MAX_PPPOE_MTU; + conn->ctrl.name = "pppoe"; + + conn->ctrl.calling_station_id = _malloc(19); + conn->ctrl.called_station_id = _malloc(19); + sprintf(conn->ctrl.calling_station_id, "%02x:%02x:%02x:%02x:%02x:%02x", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + sprintf(conn->ctrl.called_station_id, "%02x:%02x:%02x:%02x:%02x:%02x", + serv->hwaddr[0], serv->hwaddr[1], serv->hwaddr[2], serv->hwaddr[3], serv->hwaddr[4], serv->hwaddr[5]); + + ppp_init(&conn->ppp); + + conn->ppp.ctrl = &conn->ctrl; + conn->ppp.chan_name = conn->ctrl.calling_station_id; + + triton_context_register(&conn->ctx, &conn->ppp); + triton_context_wakeup(&conn->ctx); + + triton_event_fire(EV_CTRL_STARTING, &conn->ppp); + triton_event_fire(EV_CTRL_STARTED, &conn->ppp); + + conn->disc_sock = dup(serv->hnd.fd); + + return conn; +} + +static int connect_channel(struct pppoe_conn_t *conn) +{ + int sock; + struct sockaddr_pppox sp; + + sock = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_OE); + if (!sock) { + log_error("pppoe: socket(PPPOX): %s\n", strerror(errno)); + return -1; + } + + memset(&sp, 0, sizeof(sp)); + + sp.sa_family = AF_PPPOX; + sp.sa_protocol = PX_PROTO_OE; + sp.sa_addr.pppoe.sid = htons(conn->sid); + strcpy(sp.sa_addr.pppoe.dev, conn->serv->ifname); + memcpy(sp.sa_addr.pppoe.remote, conn->addr, ETH_ALEN); + + if (connect(sock, (struct sockaddr *)&sp, sizeof(sp))) { + log_error("pppoe: connect: %s\n", strerror(errno)); + close(sock); + return -1; + } + + conn->ppp.fd = sock; + + if (establish_ppp(&conn->ppp)) { + close(sock); + return -1; + } + + return 0; +} + +static void print_tag_string(struct pppoe_tag *tag) +{ + int i; + + for (i = 0; i < ntohs(tag->tag_len); i++) + log_info("%c", tag->tag_data[i]); +} + +static void print_tag_octets(struct pppoe_tag *tag) +{ + int i; + + for (i = 0; i < ntohs(tag->tag_len); i++) + log_info("%02x", (uint8_t)tag->tag_data[i]); +} + +static void print_packet(uint8_t *pack) +{ + struct ethhdr *ethhdr = (struct ethhdr *)pack; + struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); + struct pppoe_tag *tag; + int n; + + log_info("[PPPoE "); + + switch (hdr->code) { + case CODE_PADI: + log_info("PADI"); + break; + case CODE_PADO: + log_info("PADO"); + break; + case CODE_PADR: + log_info("PADR"); + break; + case CODE_PADS: + log_info("PADS"); + break; + case CODE_PADT: + log_info("PADT"); + break; + } + + log_info(" %02x:%02x:%02x:%02x:%02x:%02x => %02x:%02x:%02x:%02x:%02x:%02x", + ethhdr->h_source[0], ethhdr->h_source[1], ethhdr->h_source[2], ethhdr->h_source[3], ethhdr->h_source[4], ethhdr->h_source[5], + ethhdr->h_dest[0], ethhdr->h_dest[1], ethhdr->h_dest[2], ethhdr->h_dest[3], ethhdr->h_dest[4], ethhdr->h_dest[5]); + + log_info(" sid=%04x", ntohs(hdr->sid)); + + for (n = 0; n < ntohs(hdr->length); n += sizeof(*tag) + ntohs(tag->tag_len)) { + tag = (struct pppoe_tag *)(pack + ETH_HLEN + sizeof(*hdr) + n); + switch (ntohs(tag->tag_type)) { + case TAG_END_OF_LIST: + log_info(" "); + break; + case TAG_SERVICE_NAME: + log_info(" "); + break; + case TAG_AC_NAME: + log_info(" "); + break; + case TAG_HOST_UNIQ: + log_info(" "); + break; + case TAG_AC_COOKIE: + log_info(" "); + break; + case TAG_VENDOR_SPECIFIC: + log_info(" "); + break; + case TAG_RELAY_SESSION_ID: + log_info(" "); + break; + case TAG_SERVICE_NAME_ERROR: + log_info(" "); + break; + case TAG_AC_SYSTEM_ERROR: + log_info(" "); + break; + case TAG_GENERIC_ERROR: + log_info(" "); + break; + default: + log_info(" ", ntohs(tag->tag_type)); + break; + } + } + + log_info("]\n"); +} + +static void generate_cookie(const uint8_t *src, const uint8_t *dst, uint8_t *cookie) +{ + MD5_CTX ctx; + + MD5_Init(&ctx); + MD5_Update(&ctx, secret, SECRET_SIZE); + MD5_Update(&ctx, src, ETH_ALEN); + MD5_Update(&ctx, dst, ETH_ALEN); + MD5_Update(&ctx, conf_ac_name, strlen(conf_ac_name)); + MD5_Update(&ctx, secret, SECRET_SIZE); + MD5_Final(cookie, &ctx); +} + +static void setup_header(uint8_t *pack, const uint8_t *src, const uint8_t *dst, int code, uint16_t sid) +{ + struct ethhdr *ethhdr = (struct ethhdr *)pack; + struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); + + memcpy(ethhdr->h_source, src, ETH_ALEN); + memcpy(ethhdr->h_dest, dst, ETH_ALEN); + ethhdr->h_proto = htons(ETH_P_PPP_DISC); + + hdr->ver = 1; + hdr->type = 1; + hdr->code = code; + hdr->sid = htons(sid); + hdr->length = 0; +} + +static void add_tag(uint8_t *pack, int type, const uint8_t *data, int len) +{ + struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); + struct pppoe_tag *tag = (struct pppoe_tag *)(pack + ETH_HLEN + sizeof(*hdr) + ntohs(hdr->length)); + + tag->tag_type = htons(type); + tag->tag_len = htons(len); + memcpy(tag->tag_data, data, len); + + hdr->length = htons(ntohs(hdr->length) + sizeof(*tag) + len); +} + +static void add_tag2(uint8_t *pack, const struct pppoe_tag *t) +{ + struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); + struct pppoe_tag *tag = (struct pppoe_tag *)(pack + ETH_HLEN + sizeof(*hdr) + ntohs(hdr->length)); + + memcpy(tag, t, sizeof(*t) + ntohs(t->tag_len)); + + hdr->length = htons(ntohs(hdr->length) + sizeof(*tag) + ntohs(t->tag_len)); +} + +static void pppoe_send(int fd, const uint8_t *pack) +{ + struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); + int n, s; + + s = ETH_HLEN + sizeof(*hdr) + ntohs(hdr->length); + n = write(fd, pack, s); + if (n < 0 ) + log_error("pppoe: write: %s\n", strerror(errno)); + else if (n != s) { + log_warn("pppoe: short write %i/%i\n", n,s); + } +} + +static void pppoe_send_PADO(struct pppoe_serv_t *serv, const uint8_t *addr, const struct pppoe_tag *host_uniq, const struct pppoe_tag *relay_sid) +{ + uint8_t pack[ETHER_MAX_LEN]; + uint8_t cookie[MD5_DIGEST_LENGTH]; + + setup_header(pack, serv->hwaddr, addr, CODE_PADO, 0); + + add_tag(pack, TAG_AC_NAME, (uint8_t *)conf_ac_name, strlen(conf_ac_name)); + add_tag(pack, TAG_SERVICE_NAME, (uint8_t *)conf_service_name, strlen(conf_service_name)); + + generate_cookie(serv->hwaddr, addr, cookie); + add_tag(pack, TAG_AC_COOKIE, cookie, MD5_DIGEST_LENGTH); + + if (host_uniq) + add_tag2(pack, host_uniq); + + if (relay_sid) + add_tag2(pack, relay_sid); + + if (conf_verbose) { + log_info("send "); + print_packet(pack); + } + + pppoe_send(serv->hnd.fd, pack); +} + +static void pppoe_send_err(struct pppoe_serv_t *serv, const uint8_t *addr, const struct pppoe_tag *host_uniq, const struct pppoe_tag *relay_sid, int code, int tag_type) +{ + uint8_t pack[ETHER_MAX_LEN]; + + setup_header(pack, serv->hwaddr, addr, code, 0); + + add_tag(pack, TAG_AC_NAME, (uint8_t *)conf_ac_name, strlen(conf_ac_name)); + add_tag(pack, tag_type, NULL, 0); + + if (host_uniq) + add_tag2(pack, host_uniq); + + if (relay_sid) + add_tag2(pack, relay_sid); + + if (conf_verbose) { + log_info("send "); + print_packet(pack); + } + + pppoe_send(serv->hnd.fd, pack); +} + +static void pppoe_send_PADS(struct pppoe_conn_t *conn) +{ + uint8_t pack[ETHER_MAX_LEN]; + + setup_header(pack, conn->serv->hwaddr, conn->addr, CODE_PADS, conn->sid); + + add_tag(pack, TAG_AC_NAME, (uint8_t *)conf_ac_name, strlen(conf_ac_name)); + add_tag(pack, TAG_SERVICE_NAME, (uint8_t *)conf_service_name, strlen(conf_service_name)); + + if (conn->host_uniq) + add_tag2(pack, conn->host_uniq); + + if (conn->relay_sid) + add_tag2(pack, conn->relay_sid); + + if (conf_verbose) { + log_info("send "); + print_packet(pack); + } + + pppoe_send(conn->disc_sock, pack); +} + +static void pppoe_send_PADT(struct pppoe_conn_t *conn) +{ + uint8_t pack[ETHER_MAX_LEN]; + + setup_header(pack, conn->serv->hwaddr, conn->addr, CODE_PADT, conn->sid); + + add_tag(pack, TAG_AC_NAME, (uint8_t *)conf_ac_name, strlen(conf_ac_name)); + add_tag(pack, TAG_SERVICE_NAME, (uint8_t *)conf_service_name, strlen(conf_service_name)); + + if (conn->host_uniq) + add_tag2(pack, conn->host_uniq); + + if (conn->relay_sid) + add_tag2(pack, conn->relay_sid); + + if (conf_verbose) { + log_info("send "); + print_packet(pack); + } + + pppoe_send(conn->disc_sock, pack); +} + +static void pppoe_recv_PADI(struct pppoe_serv_t *serv, uint8_t *pack, int size) +{ + struct ethhdr *ethhdr = (struct ethhdr *)pack; + struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); + struct pppoe_tag *tag; + struct pppoe_tag *host_uniq_tag = NULL; + struct pppoe_tag *relay_sid_tag = NULL; + int n, service_match = 0; + + if (hdr->sid) { + log_warn("pppoe: discaring PADI packet (sid is not zero)\n"); + return; + } + + if (conf_verbose) { + log_info("recv "); + print_packet(pack); + } + + for (n = 0; n < ntohs(hdr->length); n += sizeof(*tag) + ntohs(tag->tag_len)) { + tag = (struct pppoe_tag *)(pack + ETH_HLEN + sizeof(*hdr) + n); + switch (ntohs(tag->tag_type)) { + case TAG_END_OF_LIST: + break; + case TAG_SERVICE_NAME: + if (tag->tag_len == 0) + service_match = 1; + else if (conf_service_name) { + if (ntohs(tag->tag_len) != strlen(conf_service_name)) + break; + if (memcmp(tag->tag_data, conf_service_name, ntohs(tag->tag_len))) + break; + service_match = 1; + } + break; + case TAG_HOST_UNIQ: + host_uniq_tag = tag; + break; + case TAG_RELAY_SESSION_ID: + relay_sid_tag = tag; + break; + } + } + + if (!service_match) { + if (conf_verbose) + log_warn("pppoe: discarding PADI packet (Service-Name mismatch)\n"); + return; + } + + pppoe_send_PADO(serv, ethhdr->h_source, host_uniq_tag, relay_sid_tag); +} + +static void pppoe_recv_PADR(struct pppoe_serv_t *serv, uint8_t *pack, int size) +{ + struct ethhdr *ethhdr = (struct ethhdr *)pack; + struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); + struct pppoe_tag *tag; + struct pppoe_tag *host_uniq_tag = NULL; + struct pppoe_tag *relay_sid_tag = NULL; + struct pppoe_tag *ac_cookie_tag = NULL; + uint8_t cookie[MD5_DIGEST_LENGTH]; + int n, service_match = 0; + struct pppoe_conn_t *conn; + + if (!memcmp(ethhdr->h_dest, bc_addr, ETH_ALEN)) { + if (conf_verbose) + log_warn("pppoe: discard PADR (destination address is broadcast)\n"); + return; + } + + if (hdr->sid) { + if (conf_verbose) + log_warn("pppoe: discaring PADR packet (sid is not zero)\n"); + return; + } + + if (conf_verbose) { + log_info("recv "); + print_packet(pack); + } + + for (n = 0; n < ntohs(hdr->length); n += sizeof(*tag) + ntohs(tag->tag_len)) { + tag = (struct pppoe_tag *)(pack + ETH_HLEN + sizeof(*hdr) + n); + switch (ntohs(tag->tag_type)) { + case TAG_END_OF_LIST: + break; + case TAG_SERVICE_NAME: + if (tag->tag_len == 0) + service_match = 1; + else if (conf_service_name) { + if (ntohs(tag->tag_len) != strlen(conf_service_name)) + break; + if (memcmp(tag->tag_data, conf_service_name, ntohs(tag->tag_len))) + break; + service_match = 1; + } + break; + case TAG_HOST_UNIQ: + host_uniq_tag = tag; + break; + case TAG_AC_COOKIE: + ac_cookie_tag = tag; + break; + case TAG_RELAY_SESSION_ID: + relay_sid_tag = tag; + break; + } + } + + if (!ac_cookie_tag) { + if (conf_verbose) + log_warn("pppoe: discard PADR packet (no AC-Cookie tag present)\n"); + return; + } + + if (ntohs(ac_cookie_tag->tag_len) != MD5_DIGEST_LENGTH) { + if (conf_verbose) + log_warn("pppoe: discard PADR packet (incorrect AC-Cookie tag length)\n"); + return; + } + + generate_cookie(serv->hwaddr, ethhdr->h_source, cookie); + + if (memcmp(cookie, ac_cookie_tag->tag_data, MD5_DIGEST_LENGTH)) { + if (conf_verbose) + log_warn("pppoe: discard PADR packet (incorrect AC-Cookie)\n"); + return; + } + + if (!service_match) { + if (conf_verbose) + log_warn("pppoe: Service-Name mismatch\n"); + pppoe_send_err(serv, ethhdr->h_source, host_uniq_tag, relay_sid_tag, CODE_PADS, TAG_SERVICE_NAME_ERROR); + return; + } + + conn = allocate_channel(serv, ethhdr->h_source, host_uniq_tag, relay_sid_tag); + if (!conn) + pppoe_send_err(serv, ethhdr->h_source, host_uniq_tag, relay_sid_tag, CODE_PADS, TAG_AC_SYSTEM_ERROR); + else { + pppoe_send_PADS(conn); + if (connect_channel(conn)) + disconnect(conn); + else + conn->ppp_started = 1; + } +} + +static void pppoe_recv_PADT(struct pppoe_serv_t *serv, uint8_t *pack) +{ + struct ethhdr *ethhdr = (struct ethhdr *)pack; + struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); + struct pppoe_conn_t *conn; + + if (!memcmp(ethhdr->h_dest, bc_addr, ETH_ALEN)) { + if (conf_verbose) + log_warn("pppoe: discard PADT (destination address is broadcast)\n"); + return; + } + + if (conf_verbose) { + log_info("recv "); + print_packet(pack); + } + + pthread_mutex_lock(&serv->lock); + conn = serv->conn[ntohs(hdr->sid)]; + if (conn && !memcmp(conn->addr, ethhdr->h_source, ETH_ALEN)) + triton_context_call(&conn->ctx, (void (*)(void *))disconnect, conn); + pthread_mutex_unlock(&serv->lock); +} + +static int pppoe_serv_read(struct triton_md_handler_t *h) +{ + struct pppoe_serv_t *serv = container_of(h, typeof(*serv), hnd); + uint8_t pack[ETHER_MAX_LEN]; + struct ethhdr *ethhdr = (struct ethhdr *)pack; + struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN); + int n; + + while (1) { + n = read(h->fd, pack, sizeof(pack)); + if (n < 0) { + if (errno == EAGAIN) + break; + log_error("pppoe: read: %s\n", strerror(errno)); + return 0; + } + + if (n < ETH_HLEN + sizeof(*hdr)) { + if (conf_verbose) + log_warn("pppoe: short packet received (%i)\n", n); + return 0; + } + + if (memcmp(ethhdr->h_dest, bc_addr, ETH_ALEN) && memcmp(ethhdr->h_dest, serv->hwaddr, ETH_ALEN)) + return 0; + + if (!memcmp(ethhdr->h_source, bc_addr, ETH_ALEN)) { + if (conf_verbose) + log_warn("pppoe: discarding packet (host address is broadcast)\n"); + return 0; + } + + if ((ethhdr->h_source[0] & 1) != 0) { + if (conf_verbose) + log_warn("pppoe: discarding packet (host address is not unicast)\n"); + return 0; + } + + if (n < ETH_HLEN + sizeof(*hdr) + ntohs(hdr->length)) { + if (conf_verbose) + log_warn("pppoe: short packet received\n"); + return 0; + } + + if (hdr->ver != 1) { + if (conf_verbose) + log_warn("pppoe: discarding packet (unsupported version %i)\n", hdr->ver); + return 0; + } + + if (hdr->type != 1) { + if (conf_verbose) + log_warn("pppoe: discarding packet (unsupported type %i)\n", hdr->type); + } + + switch (hdr->code) { + case CODE_PADI: + pppoe_recv_PADI(serv, pack, n); + break; + case CODE_PADR: + pppoe_recv_PADR(serv, pack, n); + break; + case CODE_PADT: + pppoe_recv_PADT(serv, pack); + break; + } + } + return 0; +} + +static void pppoe_serv_close(struct triton_context_t *ctx) +{ + struct pppoe_serv_t *serv = container_of(ctx, typeof(*serv), ctx); + + triton_md_unregister_handler(&serv->hnd); + close(serv->hnd.fd); + triton_context_unregister(&serv->ctx); +} + +static void pppoe_start_server(const char *ifname) +{ + struct pppoe_serv_t *serv = _malloc(sizeof(*serv)); + int sock; + int opt = 1; + struct ifreq ifr; + struct sockaddr_ll sa; + + memset(serv, 0, sizeof(*serv)); + + sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PPP_DISC)); + if (sock < 0) { + log_emerg("pppoe: socket: %s\n", strerror(errno)); + _free(serv); + return; + } + + if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt))) { + log_emerg("pppoe: setsockopt(SO_BROADCAST): %s\n", strerror(errno)); + goto out_err; + } + + strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(sock, SIOCGIFHWADDR, &ifr)) { + log_emerg("pppoe: ioctl(SIOCGIFHWADDR): %s\n", strerror(errno)); + goto out_err; + } + +#ifdef ARPHDR_ETHER + if (ifr.ifr_hwaddr.sa_family != ARPHDR_ETHER) { + log_emerg("pppoe: interface %s is not ethernet\n", ifname); + goto out_err; + } +#endif + + if ((ifr.ifr_hwaddr.sa_data[0] & 1) != 0) { + log_emerg("pppoe: interface %s has not unicast address\n", ifname); + goto out_err; + } + + memcpy(serv->hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); + + if (ioctl(sock, SIOCGIFMTU, &ifr)) { + log_emerg("pppoe: ioctl(SIOCGIFMTU): %s\n", strerror(errno)); + goto out_err; + } + + if (ifr.ifr_mtu < ETH_DATA_LEN) + log_emerg("pppoe: interface %s has MTU of %i, should be %i\n", ifname, ifr.ifr_mtu, ETH_DATA_LEN); + + if (ioctl(sock, SIOCGIFINDEX, &ifr)) { + log_emerg("pppoe: ioctl(SIOCGIFINDEX): %s\n", strerror(errno)); + goto out_err; + } + + memset(&sa, 0, sizeof(sa)); + sa.sll_family = AF_PACKET; + sa.sll_protocol = htons(ETH_P_PPP_DISC); + sa.sll_ifindex = ifr.ifr_ifindex; + + if (bind(sock, (struct sockaddr *)&sa, sizeof(sa))) { + log_emerg("pppoe: bind: %s\n", strerror(errno)); + goto out_err; + } + + if (fcntl(sock, F_SETFL, O_NONBLOCK)) { + log_emerg("pppoe: failed to set nonblocking mode: %s\n", strerror(errno)); + goto out_err; + } + + serv->ctx.close = pppoe_serv_close; + serv->hnd.fd = sock; + serv->hnd.read = pppoe_serv_read; + serv->ifname = ifname; + pthread_mutex_init(&serv->lock, NULL); + + 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); + + return; + +out_err: + close(sock); + _free(serv); +} + +static int init_secret(void) +{ + int fd; + + secret = malloc(SECRET_SIZE); + + fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + log_emerg("pppoe: cann't open /dev/urandom: %s\n", strerror(errno)); + return -1; + } + + if (read(fd, secret, SECRET_SIZE) < 0) { + log_emerg("pppoe: faild to read /dev/urandom\n", strerror(errno)); + close(fd); + return -1; + } + + close(fd); + + return 0; +} + +static void __init pppoe_init(void) +{ + struct conf_sect_t *s = conf_get_section("pppoe"); + struct conf_option_t *opt; + + conn_pool = mempool_create(sizeof(struct pppoe_conn_t)); + + if (init_secret()) + _exit(EXIT_FAILURE); + + if (!s) { + log_emerg("pppoe: no configuration, disabled...\n"); + return; + } + + list_for_each_entry(opt, &s->items, entry) { + if (!strcmp(opt->name, "interface")) + pppoe_start_server(opt->val); + else if (!strcmp(opt->name, "verbose")) { + if (atoi(opt->val) > 0) + conf_verbose = 1; + } else if (!strcmp(opt->name, "ac-name") || !strcmp(opt->name, "AC-Name")) + conf_ac_name = opt->val; + else if (!strcmp(opt->name, "service-name") || !strcmp(opt->name, "Service-Name")) + conf_service_name = opt->val; + } +} + diff --git a/accel-pptpd/ctrl/pppoe/pppoe.h b/accel-pptpd/ctrl/pppoe/pppoe.h new file mode 100644 index 00000000..05061083 --- /dev/null +++ b/accel-pptpd/ctrl/pppoe/pppoe.h @@ -0,0 +1,59 @@ +#ifndef __PPPOE_H +#define __PPPOE_H + +#include +#include + +/* PPPoE codes */ +#define CODE_PADI 0x09 +#define CODE_PADO 0x07 +#define CODE_PADR 0x19 +#define CODE_PADS 0x65 +#define CODE_PADT 0xA7 +#define CODE_SESS 0x00 + +/* PPPoE Tags */ +#define TAG_END_OF_LIST 0x0000 +#define TAG_SERVICE_NAME 0x0101 +#define TAG_AC_NAME 0x0102 +#define TAG_HOST_UNIQ 0x0103 +#define TAG_AC_COOKIE 0x0104 +#define TAG_VENDOR_SPECIFIC 0x0105 +#define TAG_RELAY_SESSION_ID 0x0110 +#define TAG_SERVICE_NAME_ERROR 0x0201 +#define TAG_AC_SYSTEM_ERROR 0x0202 +#define TAG_GENERIC_ERROR 0x0203 + +/* Discovery phase states */ +#define STATE_SENT_PADI 0 +#define STATE_RECEIVED_PADO 1 +#define STATE_SENT_PADR 2 +#define STATE_SESSION 3 +#define STATE_TERMINATED 4 + +/* Header size of a PPPoE packet */ +#define PPPOE_OVERHEAD 6 /* type, code, session, length */ +#define HDR_SIZE (sizeof(struct ethhdr) + PPPOE_OVERHEAD) +#define MAX_PPPOE_PAYLOAD (ETH_DATA_LEN - PPPOE_OVERHEAD) +#define MAX_PPPOE_MTU (MAX_PPPOE_PAYLOAD - 2) + +#define MAX_SID 65534 + +struct pppoe_tag_t +{ + struct list_head entry; + int type; + int len; +}; + +struct pppoe_packet_t +{ + uint8_t src[ETH_ALEN]; + uint8_t dst[ETH_ALEN]; + int code; + uint16_t sid; + struct list_head tags; +}; + +#endif + diff --git a/accel-pptpd/ctrl/pptp.c b/accel-pptpd/ctrl/pptp.c deleted file mode 100644 index 1151dabe..00000000 --- a/accel-pptpd/ctrl/pptp.c +++ /dev/null @@ -1,736 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "if_pppox.h" - -#include "events.h" -#include "list.h" -#include "pptp_prot.h" -#include "triton.h" -#include "log.h" -#include "ppp.h" -#include "mempool.h" -#include "iprange.h" -#include "utils.h" - -#include "memdebug.h" - -#define STATE_IDLE 0 -#define STATE_ESTB 1 -#define STATE_PPP 2 -#define STATE_FIN 3 -#define STATE_CLOSE 4 - -struct pptp_conn_t -{ - struct triton_context_t ctx; - struct triton_md_handler_t hnd; - struct triton_timer_t timeout_timer; - struct triton_timer_t echo_timer; - int call_id; - int peer_call_id; - int state; - int echo_sent; - - uint8_t *in_buf; - int in_size; - uint8_t *out_buf; - int out_size; - int out_pos; - - struct ppp_ctrl_t ctrl; - struct ppp_t ppp; -}; - -static int conf_timeout = 5; -static int conf_echo_interval = 0; -static int conf_echo_failure = 3; -static int conf_verbose = 0; - -static mempool_t conn_pool; - -static int pptp_read(struct triton_md_handler_t *h); -static int pptp_write(struct triton_md_handler_t *h); -static void pptp_timeout(struct triton_timer_t *); -static void ppp_started(struct ppp_t *); -static void ppp_finished(struct ppp_t *); - -static void disconnect(struct pptp_conn_t *conn) -{ - log_ppp_debug("pptp: disconnect\n"); - - triton_md_unregister_handler(&conn->hnd); - close(conn->hnd.fd); - - if (conn->timeout_timer.tpd) - triton_timer_del(&conn->timeout_timer); - - if (conn->echo_timer.tpd) - triton_timer_del(&conn->echo_timer); - - if (conn->state == STATE_PPP) { - conn->state = STATE_CLOSE; - ppp_terminate(&conn->ppp, 1); - } - - triton_event_fire(EV_CTRL_FINISHED, &conn->ppp); - - if (conf_verbose) - log_ppp_info("disconnected\n"); - - triton_context_unregister(&conn->ctx); - - if (conn->ppp.chan_name) - _free(conn->ppp.chan_name); - - _free(conn->in_buf); - _free(conn->out_buf); - _free(conn->ctrl.calling_station_id); - _free(conn->ctrl.called_station_id); - mempool_free(conn); -} - -static int post_msg(struct pptp_conn_t *conn, void *buf, int size) -{ - int n; - if (conn->out_size) { - log_error("pptp: buffer is not empty\n"); - return -1; - } - - n=write(conn->hnd.fd, buf, size); - if (n < 0) { - if (errno == EINTR || errno == EAGAIN) - n = 0; - else { - if (errno != EPIPE) { - if (conf_verbose) - log_ppp_info("pptp: write: %s\n", strerror(errno)); - return -1; - } - } - } - - if ( nout_buf, buf + n, size - n); - triton_md_enable_handler(&conn->hnd, MD_MODE_WRITE); - } - - return 0; -} - -static int send_pptp_stop_ctrl_conn_rqst(struct pptp_conn_t *conn, int reason) -{ - struct pptp_stop_ctrl_conn msg = { - .header = PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RQST), - .reason_result = hton8(reason), - }; - - if (conf_verbose) - log_ppp_info("send [PPTP Stop-Ctrl-Conn-Request ]\n", reason); - - return post_msg(conn, &msg, sizeof(msg)); -} - -static int send_pptp_stop_ctrl_conn_rply(struct pptp_conn_t *conn, int reason, int err_code) -{ - struct pptp_stop_ctrl_conn msg = { - .header = PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RPLY), - .reason_result = hton8(reason), - .error_code = hton8(err_code), - }; - - if (conf_verbose) - log_ppp_info("send [PPTP Stop-Ctrl-Conn-Reply ]\n", msg.reason_result, msg.error_code); - - return post_msg(conn, &msg, sizeof(msg)); -} -static int pptp_stop_ctrl_conn_rqst(struct pptp_conn_t *conn) -{ - 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-Request ]\n", msg->reason_result); - - send_pptp_stop_ctrl_conn_rply(conn, PPTP_CONN_STOP_OK, 0); - - return -1; -} - -static int pptp_stop_ctrl_conn_rply(struct pptp_conn_t *conn) -{ - 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 ]\n", msg->reason_result, msg->error_code); - return -1; -} - -static int send_pptp_start_ctrl_conn_rply(struct pptp_conn_t *conn, int res_code, int err_code) -{ - 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, - .framing_cap = htonl(3), - .bearer_cap = htonl(3), - .max_channels = htons(1), - .firmware_rev = htons(PPTP_FIRMWARE_VERSION), - }; - - memset(msg.hostname, 0, sizeof(msg.hostname)); - strcpy((char*)msg.hostname, PPTP_HOSTNAME); - - memset(msg.vendor, 0, sizeof(msg.vendor)); - strcpy((char*)msg.vendor, PPTP_VENDOR); - - if (conf_verbose) - log_ppp_info("send [PPTP Start-Ctrl-Conn-Reply ]\n", msg.version, msg.result_code, msg.error_code, ntohl(msg.framing_cap), ntohl(msg.bearer_cap), ntohs(msg.max_channels)); - - return post_msg(conn, &msg, sizeof(msg)); -} - -static int pptp_start_ctrl_conn_rqst(struct pptp_conn_t *conn) -{ - struct pptp_start_ctrl_conn *msg = (struct pptp_start_ctrl_conn *)conn->in_buf; - - if (conf_verbose) - log_ppp_info("recv [PPTP Start-Ctrl-Conn-Request ]\n", msg->version, ntohl(msg->framing_cap), ntohl(msg->bearer_cap), ntohs(msg->max_channels)); - - if (conn->state != STATE_IDLE) { - log_ppp_warn("unexpected PPTP_START_CTRL_CONN_RQST\n"); - if (send_pptp_start_ctrl_conn_rply(conn, PPTP_CONN_RES_EXISTS, 0)) - return -1; - return 0; - } - - if (msg->version != htons(PPTP_VERSION)) { - log_ppp_warn("PPTP version mismatch: expecting %x, received %s\n", PPTP_VERSION, msg->version); - if (send_pptp_start_ctrl_conn_rply(conn, PPTP_CONN_RES_PROTOCOL, 0)) - return -1; - return 0; - } - /*if (!(ntohl(msg->framing_cap) & PPTP_FRAME_SYNC)) { - log_ppp_warn("connection does not supports sync mode\n"); - if (send_pptp_start_ctrl_conn_rply(conn, PPTP_CONN_RES_GE, 0)) - return -1; - return 0; - }*/ - if (send_pptp_start_ctrl_conn_rply(conn, PPTP_CONN_RES_SUCCESS, 0)) - return -1; - - triton_timer_mod(&conn->timeout_timer, 0); - - conn->state = STATE_ESTB; - - return 0; -} - -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) -{ - 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, - }; - - if (conf_verbose) - log_ppp_info("send [PPTP Outgoing-Call-Reply ]\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)); - - return post_msg(conn, &msg, sizeof(msg)); -} - -static int pptp_out_call_rqst(struct pptp_conn_t *conn) -{ - struct pptp_out_call_rqst *msg = (struct pptp_out_call_rqst *)conn->in_buf; - struct sockaddr_pppox src_addr, dst_addr; - struct sockaddr_in addr; - socklen_t addrlen; - int pptp_sock; - - if (conf_verbose) - log_ppp_info("recv [PPTP Outgoing-Call-Request ]\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)); - - if (conn->state != STATE_ESTB) { - log_ppp_warn("unexpected PPTP_OUT_CALL_RQST\n"); - if (send_pptp_out_call_rply(conn, msg, 0, PPTP_CALL_RES_GE, PPTP_GE_NOCONN)) - return -1; - return 0; - } - - 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) { - log_ppp_error("failed to create PPTP socket (%s)\n", strerror(errno)); - return -1; - } - if (bind(pptp_sock, (struct sockaddr*)&src_addr, sizeof(src_addr))) { - log_ppp_error("failed to bind PPTP socket (%s)\n", strerror(errno)); - close(pptp_sock); - return -1; - } - addrlen = sizeof(src_addr); - getsockname(pptp_sock, (struct sockaddr*)&src_addr, &addrlen); - - if (connect(pptp_sock, (struct sockaddr*)&dst_addr, sizeof(dst_addr))) { - log_ppp_error("failed to connect PPTP socket (%s)\n", strerror(errno)); - close(pptp_sock); - return -1; - } - - if (send_pptp_out_call_rply(conn, msg, src_addr.sa_addr.pptp.call_id, PPTP_CALL_RES_OK, 0)) - return -1; - - conn->call_id = src_addr.sa_addr.pptp.call_id; - conn->peer_call_id = msg->call_id; - conn->ppp.fd = pptp_sock; - conn->ppp.chan_name = _strdup(inet_ntoa(dst_addr.sa_addr.pptp.sin_addr)); - - triton_event_fire(EV_CTRL_STARTED, &conn->ppp); - - if (establish_ppp(&conn->ppp)) { - close(pptp_sock); - //if (send_pptp_stop_ctrl_conn_rqst(conn, 0, 0)) - conn->state = STATE_FIN; - return -1; - } - conn->state = STATE_PPP; - - if (conn->timeout_timer.tpd) - triton_timer_del(&conn->timeout_timer); - - if (conf_echo_interval) { - conn->echo_timer.period = conf_echo_interval * 1000; - triton_timer_add(&conn->ctx, &conn->echo_timer, 0); - } - - return 0; -} - -static int send_pptp_call_disconnect_notify(struct pptp_conn_t *conn, int result) -{ - 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) - log_ppp_info("send [PPTP Call-Disconnect-Notify ]\n", ntohs(msg.call_id), msg.result_code, msg.error_code, msg.cause_code); - - 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 ]\n", ntohs(rqst->call_id)); - - if (conn->state == STATE_PPP) { - conn->state = STATE_CLOSE; - ppp_terminate(&conn->ppp, 1); - } - - return send_pptp_call_disconnect_notify(conn, 4); -} - -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 = { - .header = PPTP_HEADER_CTRL(PPTP_ECHO_RPLY), - .identifier = in_msg->identifier, - .result_code = 1, - }; - - if (conf_verbose) { - log_ppp_info("recv [PPTP Echo-Request ]\n", in_msg->identifier); - log_ppp_info("send [PPTP Echo-Reply ]\n", out_msg.identifier); - } - - return post_msg(conn, &out_msg, sizeof(out_msg)); -} - -static int pptp_echo_rply(struct pptp_conn_t *conn) -{ - struct pptp_echo_rply *msg = (struct pptp_echo_rply *)conn->in_buf; - - if (conf_verbose) - log_ppp_info("recv [PPTP Echo-Reply ]\n", msg->identifier); - - if (msg->identifier != conn->echo_sent) { - log_ppp_warn("pptp:echo: identifier mismatch\n"); - //return -1; - } - conn->echo_sent = 0; - return 0; -} -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), - }; - - if (++conn->echo_sent == conf_echo_failure) { - log_ppp_warn("pptp: no echo reply\n"); - disconnect(conn); - return; - } - - conn->echo_sent = random(); - msg.identifier = conn->echo_sent; - - if (conf_verbose) - log_ppp_info("send [PPTP Echo-Request ]\n", msg.identifier); - - if (post_msg(conn, &msg, sizeof(msg))) - disconnect(conn); -} - -static int process_packet(struct pptp_conn_t *conn) -{ - struct pptp_header *hdr = (struct pptp_header *)conn->in_buf; - 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); - case PPTP_STOP_CTRL_CONN_RPLY: - return pptp_stop_ctrl_conn_rply(conn); - case PPTP_OUT_CALL_RQST: - return pptp_out_call_rqst(conn); - case PPTP_ECHO_RQST: - return pptp_echo_rqst(conn); - case PPTP_ECHO_RPLY: - return pptp_echo_rply(conn); - case PPTP_CALL_CLEAR_RQST: - return pptp_call_clear_rqst(conn); - case PPTP_SET_LINK_INFO: - if (conf_verbose) - log_ppp_info("recv [PPTP Set-Link-Info]\n"); - return 0; - default: - log_ppp_warn("recv [PPTP Unknown (%x)]\n", ntohs(hdr->ctrl_type)); - } - return 0; -} - -static int pptp_read(struct triton_md_handler_t *h) -{ - struct pptp_conn_t *conn=container_of(h,typeof(*conn),hnd); - struct pptp_header *hdr=(struct pptp_header *)conn->in_buf; - int n; - - while(1) { - n = read(h->fd, conn->in_buf + conn->in_size, PPTP_CTRL_SIZE_MAX - conn->in_size); - if (n < 0) { - if (errno == EINTR) - continue; - if (errno == EAGAIN) - return 0; - log_ppp_error("pptp: read: %s\n",strerror(errno)); - goto drop; - } - if (n == 0) { - if (conf_verbose) - log_ppp_info("pptp: disconnect by peer\n"); - goto drop; - } - conn->in_size += n; - if (conn->in_size >= sizeof(*hdr)) { - if (hdr->magic != htonl(PPTP_MAGIC)) { - log_ppp_error("pptp: invalid magic\n"); - goto drop; - } - if (ntohs(hdr->length) >= PPTP_CTRL_SIZE_MAX) { - log_ppp_error("pptp: message is too long\n"); - goto drop; - } - if (ntohs(hdr->length) > conn->in_size) - 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"); - goto drop; - } - if (process_packet(conn)) - goto drop; - conn->in_size -= ntohs(hdr->length); - if (conn->in_size) - memmove(conn->in_buf, conn->in_buf + ntohs(hdr->length), conn->in_size); - } - } - } -drop: - disconnect(conn); - return 1; -} -static int pptp_write(struct triton_md_handler_t *h) -{ - struct pptp_conn_t *conn = container_of(h, typeof(*conn), hnd); - int n; - - 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) { - if (conf_verbose) - log_ppp_info("pptp: post_msg: %s\n", strerror(errno)); - } - disconnect(conn); - return 1; - } - } - - 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; - } - } -} -static void pptp_timeout(struct triton_timer_t *t) -{ - struct pptp_conn_t *conn = container_of(t, typeof(*conn), timeout_timer); - disconnect(conn); -} -static void pptp_close(struct triton_context_t *ctx) -{ - struct pptp_conn_t *conn = container_of(ctx, typeof(*conn), ctx); - if (conn->state == STATE_PPP) { - conn->state = STATE_CLOSE; - ppp_terminate(&conn->ppp, 1); - if (send_pptp_call_disconnect_notify(conn, 3)) { - triton_context_call(&conn->ctx, (void (*)(void*))disconnect, conn); - return; - } - } else { - if (send_pptp_stop_ctrl_conn_rqst(conn, 0)) { - triton_context_call(&conn->ctx, (void (*)(void*))disconnect, conn); - return; - } - } - - if (conn->timeout_timer.tpd) - triton_timer_mod(&conn->timeout_timer, 0); - else - triton_timer_add(ctx, &conn->timeout_timer, 0); -} -static void ppp_started(struct ppp_t *ppp) -{ - log_ppp_debug("pptp: ppp started\n"); -} -static void ppp_finished(struct ppp_t *ppp) -{ - struct pptp_conn_t *conn = container_of(ppp, typeof(*conn), ppp); - - if (conn->state != STATE_CLOSE) { - log_ppp_debug("pptp: ppp finished\n"); - conn->state = STATE_CLOSE; - - if (send_pptp_call_disconnect_notify(conn, 3)) - triton_context_call(&conn->ctx, (void (*)(void*))disconnect, conn); - else if (send_pptp_stop_ctrl_conn_rqst(conn, 0)) - 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); - } - } -} - -//================================== - -struct pptp_serv_t -{ - struct triton_context_t ctx; - struct triton_md_handler_t hnd; -}; - -static int pptp_connect(struct triton_md_handler_t *h) -{ - struct sockaddr_in addr; - socklen_t size = sizeof(addr); - int sock; - struct pptp_conn_t *conn; - - while(1) { - sock = accept(h->fd, (struct sockaddr *)&addr, &size); - if (sock < 0) { - if (errno == EAGAIN) - return 0; - log_error("pptp: accept failed: %s\n", strerror(errno)); - continue; - } - - log_info("pptp: new connection from %s\n", inet_ntoa(addr.sin_addr)); - - 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; - } - - if (fcntl(sock, F_SETFL, O_NONBLOCK)) { - log_error("pptp: failed to set nonblocking mode: %s, closing connection...\n", strerror(errno)); - close(sock); - continue; - } - - conn = mempool_alloc(conn_pool); - memset(conn, 0, sizeof(*conn)); - conn->hnd.fd = sock; - conn->hnd.read = pptp_read; - conn->hnd.write = pptp_write; - conn->ctx.close = pptp_close; - conn->ctx.before_switch = log_switch; - conn->in_buf = _malloc(PPTP_CTRL_SIZE_MAX); - conn->out_buf = _malloc(PPTP_CTRL_SIZE_MAX); - conn->timeout_timer.expire = pptp_timeout; - conn->timeout_timer.period = conf_timeout * 1000; - conn->echo_timer.expire = pptp_send_echo; - conn->ctrl.ctx = &conn->ctx; - conn->ctrl.started = ppp_started; - conn->ctrl.finished = ppp_finished; - conn->ctrl.max_mtu = PPTP_MAX_MTU; - conn->ctrl.name = "pptp"; - - 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); - - ppp_init(&conn->ppp); - conn->ppp.ctrl = &conn->ctrl; - - triton_context_register(&conn->ctx, &conn->ppp); - triton_md_register_handler(&conn->ctx, &conn->hnd); - triton_md_enable_handler(&conn->hnd,MD_MODE_READ); - triton_timer_add(&conn->ctx, &conn->timeout_timer, 0); - triton_context_wakeup(&conn->ctx); - - triton_event_fire(EV_CTRL_STARTING, &conn->ppp); - } - return 0; -} -static void pptp_serv_close(struct triton_context_t *ctx) -{ - struct pptp_serv_t *s=container_of(ctx,typeof(*s),ctx); - triton_md_unregister_handler(&s->hnd); - close(s->hnd.fd); - triton_context_unregister(ctx); -} - -static struct pptp_serv_t serv= -{ - .hnd.read=pptp_connect, - .ctx.close=pptp_serv_close, -}; - -static void __init pptp_init(void) -{ - struct sockaddr_in addr; - char *opt; - - serv.hnd.fd = socket(PF_INET, SOCK_STREAM, 0); - if (serv.hnd.fd < 0) { - log_emerg("pptp: failed to create server socket: %s\n", strerror(errno)); - return; - } - addr.sin_family = AF_INET; - addr.sin_port = htons(PPTP_PORT); - - opt = conf_get_opt("pptp", "bind"); - if (opt) - addr.sin_addr.s_addr = inet_addr(opt); - else - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - setsockopt(serv.hnd.fd, SOL_SOCKET, SO_REUSEADDR, &serv.hnd.fd, 4); - if (bind (serv.hnd.fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) { - log_emerg("pptp: failed to bind socket: %s\n", strerror(errno)); - close(serv.hnd.fd); - return; - } - - if (listen (serv.hnd.fd, 100) < 0) { - log_emerg("pptp: failed to listen socket: %s\n", strerror(errno)); - close(serv.hnd.fd); - return; - } - - if (fcntl(serv.hnd.fd, F_SETFL, O_NONBLOCK)) { - log_emerg("pptp: failed to set nonblocking mode: %s\n", strerror(errno)); - close(serv.hnd.fd); - return; - } - - opt = conf_get_opt("pptp", "timeout"); - if (opt && atoi(opt) > 0) - conf_timeout = atoi(opt); - - opt = conf_get_opt("pptp", "echo-interval"); - if (opt && atoi(opt) >= 0) - conf_echo_interval = atoi(opt); - - 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; - - 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); -} - diff --git a/accel-pptpd/ctrl/pptp/CMakeLists.txt b/accel-pptpd/ctrl/pptp/CMakeLists.txt new file mode 100644 index 00000000..19e53b27 --- /dev/null +++ b/accel-pptpd/ctrl/pptp/CMakeLists.txt @@ -0,0 +1,5 @@ +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +ADD_LIBRARY(pptp SHARED pptp.c) + +INSTALL(TARGETS pptp LIBRARY DESTINATION usr/lib/accel-pptp ) diff --git a/accel-pptpd/ctrl/pptp/pptp.c b/accel-pptpd/ctrl/pptp/pptp.c new file mode 100644 index 00000000..1151dabe --- /dev/null +++ b/accel-pptpd/ctrl/pptp/pptp.c @@ -0,0 +1,736 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "if_pppox.h" + +#include "events.h" +#include "list.h" +#include "pptp_prot.h" +#include "triton.h" +#include "log.h" +#include "ppp.h" +#include "mempool.h" +#include "iprange.h" +#include "utils.h" + +#include "memdebug.h" + +#define STATE_IDLE 0 +#define STATE_ESTB 1 +#define STATE_PPP 2 +#define STATE_FIN 3 +#define STATE_CLOSE 4 + +struct pptp_conn_t +{ + struct triton_context_t ctx; + struct triton_md_handler_t hnd; + struct triton_timer_t timeout_timer; + struct triton_timer_t echo_timer; + int call_id; + int peer_call_id; + int state; + int echo_sent; + + uint8_t *in_buf; + int in_size; + uint8_t *out_buf; + int out_size; + int out_pos; + + struct ppp_ctrl_t ctrl; + struct ppp_t ppp; +}; + +static int conf_timeout = 5; +static int conf_echo_interval = 0; +static int conf_echo_failure = 3; +static int conf_verbose = 0; + +static mempool_t conn_pool; + +static int pptp_read(struct triton_md_handler_t *h); +static int pptp_write(struct triton_md_handler_t *h); +static void pptp_timeout(struct triton_timer_t *); +static void ppp_started(struct ppp_t *); +static void ppp_finished(struct ppp_t *); + +static void disconnect(struct pptp_conn_t *conn) +{ + log_ppp_debug("pptp: disconnect\n"); + + triton_md_unregister_handler(&conn->hnd); + close(conn->hnd.fd); + + if (conn->timeout_timer.tpd) + triton_timer_del(&conn->timeout_timer); + + if (conn->echo_timer.tpd) + triton_timer_del(&conn->echo_timer); + + if (conn->state == STATE_PPP) { + conn->state = STATE_CLOSE; + ppp_terminate(&conn->ppp, 1); + } + + triton_event_fire(EV_CTRL_FINISHED, &conn->ppp); + + if (conf_verbose) + log_ppp_info("disconnected\n"); + + triton_context_unregister(&conn->ctx); + + if (conn->ppp.chan_name) + _free(conn->ppp.chan_name); + + _free(conn->in_buf); + _free(conn->out_buf); + _free(conn->ctrl.calling_station_id); + _free(conn->ctrl.called_station_id); + mempool_free(conn); +} + +static int post_msg(struct pptp_conn_t *conn, void *buf, int size) +{ + int n; + if (conn->out_size) { + log_error("pptp: buffer is not empty\n"); + return -1; + } + + n=write(conn->hnd.fd, buf, size); + if (n < 0) { + if (errno == EINTR || errno == EAGAIN) + n = 0; + else { + if (errno != EPIPE) { + if (conf_verbose) + log_ppp_info("pptp: write: %s\n", strerror(errno)); + return -1; + } + } + } + + if ( nout_buf, buf + n, size - n); + triton_md_enable_handler(&conn->hnd, MD_MODE_WRITE); + } + + return 0; +} + +static int send_pptp_stop_ctrl_conn_rqst(struct pptp_conn_t *conn, int reason) +{ + struct pptp_stop_ctrl_conn msg = { + .header = PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RQST), + .reason_result = hton8(reason), + }; + + if (conf_verbose) + log_ppp_info("send [PPTP Stop-Ctrl-Conn-Request ]\n", reason); + + return post_msg(conn, &msg, sizeof(msg)); +} + +static int send_pptp_stop_ctrl_conn_rply(struct pptp_conn_t *conn, int reason, int err_code) +{ + struct pptp_stop_ctrl_conn msg = { + .header = PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RPLY), + .reason_result = hton8(reason), + .error_code = hton8(err_code), + }; + + if (conf_verbose) + log_ppp_info("send [PPTP Stop-Ctrl-Conn-Reply ]\n", msg.reason_result, msg.error_code); + + return post_msg(conn, &msg, sizeof(msg)); +} +static int pptp_stop_ctrl_conn_rqst(struct pptp_conn_t *conn) +{ + 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-Request ]\n", msg->reason_result); + + send_pptp_stop_ctrl_conn_rply(conn, PPTP_CONN_STOP_OK, 0); + + return -1; +} + +static int pptp_stop_ctrl_conn_rply(struct pptp_conn_t *conn) +{ + 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 ]\n", msg->reason_result, msg->error_code); + return -1; +} + +static int send_pptp_start_ctrl_conn_rply(struct pptp_conn_t *conn, int res_code, int err_code) +{ + 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, + .framing_cap = htonl(3), + .bearer_cap = htonl(3), + .max_channels = htons(1), + .firmware_rev = htons(PPTP_FIRMWARE_VERSION), + }; + + memset(msg.hostname, 0, sizeof(msg.hostname)); + strcpy((char*)msg.hostname, PPTP_HOSTNAME); + + memset(msg.vendor, 0, sizeof(msg.vendor)); + strcpy((char*)msg.vendor, PPTP_VENDOR); + + if (conf_verbose) + log_ppp_info("send [PPTP Start-Ctrl-Conn-Reply ]\n", msg.version, msg.result_code, msg.error_code, ntohl(msg.framing_cap), ntohl(msg.bearer_cap), ntohs(msg.max_channels)); + + return post_msg(conn, &msg, sizeof(msg)); +} + +static int pptp_start_ctrl_conn_rqst(struct pptp_conn_t *conn) +{ + struct pptp_start_ctrl_conn *msg = (struct pptp_start_ctrl_conn *)conn->in_buf; + + if (conf_verbose) + log_ppp_info("recv [PPTP Start-Ctrl-Conn-Request ]\n", msg->version, ntohl(msg->framing_cap), ntohl(msg->bearer_cap), ntohs(msg->max_channels)); + + if (conn->state != STATE_IDLE) { + log_ppp_warn("unexpected PPTP_START_CTRL_CONN_RQST\n"); + if (send_pptp_start_ctrl_conn_rply(conn, PPTP_CONN_RES_EXISTS, 0)) + return -1; + return 0; + } + + if (msg->version != htons(PPTP_VERSION)) { + log_ppp_warn("PPTP version mismatch: expecting %x, received %s\n", PPTP_VERSION, msg->version); + if (send_pptp_start_ctrl_conn_rply(conn, PPTP_CONN_RES_PROTOCOL, 0)) + return -1; + return 0; + } + /*if (!(ntohl(msg->framing_cap) & PPTP_FRAME_SYNC)) { + log_ppp_warn("connection does not supports sync mode\n"); + if (send_pptp_start_ctrl_conn_rply(conn, PPTP_CONN_RES_GE, 0)) + return -1; + return 0; + }*/ + if (send_pptp_start_ctrl_conn_rply(conn, PPTP_CONN_RES_SUCCESS, 0)) + return -1; + + triton_timer_mod(&conn->timeout_timer, 0); + + conn->state = STATE_ESTB; + + return 0; +} + +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) +{ + 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, + }; + + if (conf_verbose) + log_ppp_info("send [PPTP Outgoing-Call-Reply ]\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)); + + return post_msg(conn, &msg, sizeof(msg)); +} + +static int pptp_out_call_rqst(struct pptp_conn_t *conn) +{ + struct pptp_out_call_rqst *msg = (struct pptp_out_call_rqst *)conn->in_buf; + struct sockaddr_pppox src_addr, dst_addr; + struct sockaddr_in addr; + socklen_t addrlen; + int pptp_sock; + + if (conf_verbose) + log_ppp_info("recv [PPTP Outgoing-Call-Request ]\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)); + + if (conn->state != STATE_ESTB) { + log_ppp_warn("unexpected PPTP_OUT_CALL_RQST\n"); + if (send_pptp_out_call_rply(conn, msg, 0, PPTP_CALL_RES_GE, PPTP_GE_NOCONN)) + return -1; + return 0; + } + + 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) { + log_ppp_error("failed to create PPTP socket (%s)\n", strerror(errno)); + return -1; + } + if (bind(pptp_sock, (struct sockaddr*)&src_addr, sizeof(src_addr))) { + log_ppp_error("failed to bind PPTP socket (%s)\n", strerror(errno)); + close(pptp_sock); + return -1; + } + addrlen = sizeof(src_addr); + getsockname(pptp_sock, (struct sockaddr*)&src_addr, &addrlen); + + if (connect(pptp_sock, (struct sockaddr*)&dst_addr, sizeof(dst_addr))) { + log_ppp_error("failed to connect PPTP socket (%s)\n", strerror(errno)); + close(pptp_sock); + return -1; + } + + if (send_pptp_out_call_rply(conn, msg, src_addr.sa_addr.pptp.call_id, PPTP_CALL_RES_OK, 0)) + return -1; + + conn->call_id = src_addr.sa_addr.pptp.call_id; + conn->peer_call_id = msg->call_id; + conn->ppp.fd = pptp_sock; + conn->ppp.chan_name = _strdup(inet_ntoa(dst_addr.sa_addr.pptp.sin_addr)); + + triton_event_fire(EV_CTRL_STARTED, &conn->ppp); + + if (establish_ppp(&conn->ppp)) { + close(pptp_sock); + //if (send_pptp_stop_ctrl_conn_rqst(conn, 0, 0)) + conn->state = STATE_FIN; + return -1; + } + conn->state = STATE_PPP; + + if (conn->timeout_timer.tpd) + triton_timer_del(&conn->timeout_timer); + + if (conf_echo_interval) { + conn->echo_timer.period = conf_echo_interval * 1000; + triton_timer_add(&conn->ctx, &conn->echo_timer, 0); + } + + return 0; +} + +static int send_pptp_call_disconnect_notify(struct pptp_conn_t *conn, int result) +{ + 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) + log_ppp_info("send [PPTP Call-Disconnect-Notify ]\n", ntohs(msg.call_id), msg.result_code, msg.error_code, msg.cause_code); + + 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 ]\n", ntohs(rqst->call_id)); + + if (conn->state == STATE_PPP) { + conn->state = STATE_CLOSE; + ppp_terminate(&conn->ppp, 1); + } + + return send_pptp_call_disconnect_notify(conn, 4); +} + +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 = { + .header = PPTP_HEADER_CTRL(PPTP_ECHO_RPLY), + .identifier = in_msg->identifier, + .result_code = 1, + }; + + if (conf_verbose) { + log_ppp_info("recv [PPTP Echo-Request ]\n", in_msg->identifier); + log_ppp_info("send [PPTP Echo-Reply ]\n", out_msg.identifier); + } + + return post_msg(conn, &out_msg, sizeof(out_msg)); +} + +static int pptp_echo_rply(struct pptp_conn_t *conn) +{ + struct pptp_echo_rply *msg = (struct pptp_echo_rply *)conn->in_buf; + + if (conf_verbose) + log_ppp_info("recv [PPTP Echo-Reply ]\n", msg->identifier); + + if (msg->identifier != conn->echo_sent) { + log_ppp_warn("pptp:echo: identifier mismatch\n"); + //return -1; + } + conn->echo_sent = 0; + return 0; +} +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), + }; + + if (++conn->echo_sent == conf_echo_failure) { + log_ppp_warn("pptp: no echo reply\n"); + disconnect(conn); + return; + } + + conn->echo_sent = random(); + msg.identifier = conn->echo_sent; + + if (conf_verbose) + log_ppp_info("send [PPTP Echo-Request ]\n", msg.identifier); + + if (post_msg(conn, &msg, sizeof(msg))) + disconnect(conn); +} + +static int process_packet(struct pptp_conn_t *conn) +{ + struct pptp_header *hdr = (struct pptp_header *)conn->in_buf; + 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); + case PPTP_STOP_CTRL_CONN_RPLY: + return pptp_stop_ctrl_conn_rply(conn); + case PPTP_OUT_CALL_RQST: + return pptp_out_call_rqst(conn); + case PPTP_ECHO_RQST: + return pptp_echo_rqst(conn); + case PPTP_ECHO_RPLY: + return pptp_echo_rply(conn); + case PPTP_CALL_CLEAR_RQST: + return pptp_call_clear_rqst(conn); + case PPTP_SET_LINK_INFO: + if (conf_verbose) + log_ppp_info("recv [PPTP Set-Link-Info]\n"); + return 0; + default: + log_ppp_warn("recv [PPTP Unknown (%x)]\n", ntohs(hdr->ctrl_type)); + } + return 0; +} + +static int pptp_read(struct triton_md_handler_t *h) +{ + struct pptp_conn_t *conn=container_of(h,typeof(*conn),hnd); + struct pptp_header *hdr=(struct pptp_header *)conn->in_buf; + int n; + + while(1) { + n = read(h->fd, conn->in_buf + conn->in_size, PPTP_CTRL_SIZE_MAX - conn->in_size); + if (n < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) + return 0; + log_ppp_error("pptp: read: %s\n",strerror(errno)); + goto drop; + } + if (n == 0) { + if (conf_verbose) + log_ppp_info("pptp: disconnect by peer\n"); + goto drop; + } + conn->in_size += n; + if (conn->in_size >= sizeof(*hdr)) { + if (hdr->magic != htonl(PPTP_MAGIC)) { + log_ppp_error("pptp: invalid magic\n"); + goto drop; + } + if (ntohs(hdr->length) >= PPTP_CTRL_SIZE_MAX) { + log_ppp_error("pptp: message is too long\n"); + goto drop; + } + if (ntohs(hdr->length) > conn->in_size) + 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"); + goto drop; + } + if (process_packet(conn)) + goto drop; + conn->in_size -= ntohs(hdr->length); + if (conn->in_size) + memmove(conn->in_buf, conn->in_buf + ntohs(hdr->length), conn->in_size); + } + } + } +drop: + disconnect(conn); + return 1; +} +static int pptp_write(struct triton_md_handler_t *h) +{ + struct pptp_conn_t *conn = container_of(h, typeof(*conn), hnd); + int n; + + 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) { + if (conf_verbose) + log_ppp_info("pptp: post_msg: %s\n", strerror(errno)); + } + disconnect(conn); + return 1; + } + } + + 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; + } + } +} +static void pptp_timeout(struct triton_timer_t *t) +{ + struct pptp_conn_t *conn = container_of(t, typeof(*conn), timeout_timer); + disconnect(conn); +} +static void pptp_close(struct triton_context_t *ctx) +{ + struct pptp_conn_t *conn = container_of(ctx, typeof(*conn), ctx); + if (conn->state == STATE_PPP) { + conn->state = STATE_CLOSE; + ppp_terminate(&conn->ppp, 1); + if (send_pptp_call_disconnect_notify(conn, 3)) { + triton_context_call(&conn->ctx, (void (*)(void*))disconnect, conn); + return; + } + } else { + if (send_pptp_stop_ctrl_conn_rqst(conn, 0)) { + triton_context_call(&conn->ctx, (void (*)(void*))disconnect, conn); + return; + } + } + + if (conn->timeout_timer.tpd) + triton_timer_mod(&conn->timeout_timer, 0); + else + triton_timer_add(ctx, &conn->timeout_timer, 0); +} +static void ppp_started(struct ppp_t *ppp) +{ + log_ppp_debug("pptp: ppp started\n"); +} +static void ppp_finished(struct ppp_t *ppp) +{ + struct pptp_conn_t *conn = container_of(ppp, typeof(*conn), ppp); + + if (conn->state != STATE_CLOSE) { + log_ppp_debug("pptp: ppp finished\n"); + conn->state = STATE_CLOSE; + + if (send_pptp_call_disconnect_notify(conn, 3)) + triton_context_call(&conn->ctx, (void (*)(void*))disconnect, conn); + else if (send_pptp_stop_ctrl_conn_rqst(conn, 0)) + 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); + } + } +} + +//================================== + +struct pptp_serv_t +{ + struct triton_context_t ctx; + struct triton_md_handler_t hnd; +}; + +static int pptp_connect(struct triton_md_handler_t *h) +{ + struct sockaddr_in addr; + socklen_t size = sizeof(addr); + int sock; + struct pptp_conn_t *conn; + + while(1) { + sock = accept(h->fd, (struct sockaddr *)&addr, &size); + if (sock < 0) { + if (errno == EAGAIN) + return 0; + log_error("pptp: accept failed: %s\n", strerror(errno)); + continue; + } + + log_info("pptp: new connection from %s\n", inet_ntoa(addr.sin_addr)); + + 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; + } + + if (fcntl(sock, F_SETFL, O_NONBLOCK)) { + log_error("pptp: failed to set nonblocking mode: %s, closing connection...\n", strerror(errno)); + close(sock); + continue; + } + + conn = mempool_alloc(conn_pool); + memset(conn, 0, sizeof(*conn)); + conn->hnd.fd = sock; + conn->hnd.read = pptp_read; + conn->hnd.write = pptp_write; + conn->ctx.close = pptp_close; + conn->ctx.before_switch = log_switch; + conn->in_buf = _malloc(PPTP_CTRL_SIZE_MAX); + conn->out_buf = _malloc(PPTP_CTRL_SIZE_MAX); + conn->timeout_timer.expire = pptp_timeout; + conn->timeout_timer.period = conf_timeout * 1000; + conn->echo_timer.expire = pptp_send_echo; + conn->ctrl.ctx = &conn->ctx; + conn->ctrl.started = ppp_started; + conn->ctrl.finished = ppp_finished; + conn->ctrl.max_mtu = PPTP_MAX_MTU; + conn->ctrl.name = "pptp"; + + 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); + + ppp_init(&conn->ppp); + conn->ppp.ctrl = &conn->ctrl; + + triton_context_register(&conn->ctx, &conn->ppp); + triton_md_register_handler(&conn->ctx, &conn->hnd); + triton_md_enable_handler(&conn->hnd,MD_MODE_READ); + triton_timer_add(&conn->ctx, &conn->timeout_timer, 0); + triton_context_wakeup(&conn->ctx); + + triton_event_fire(EV_CTRL_STARTING, &conn->ppp); + } + return 0; +} +static void pptp_serv_close(struct triton_context_t *ctx) +{ + struct pptp_serv_t *s=container_of(ctx,typeof(*s),ctx); + triton_md_unregister_handler(&s->hnd); + close(s->hnd.fd); + triton_context_unregister(ctx); +} + +static struct pptp_serv_t serv= +{ + .hnd.read=pptp_connect, + .ctx.close=pptp_serv_close, +}; + +static void __init pptp_init(void) +{ + struct sockaddr_in addr; + char *opt; + + serv.hnd.fd = socket(PF_INET, SOCK_STREAM, 0); + if (serv.hnd.fd < 0) { + log_emerg("pptp: failed to create server socket: %s\n", strerror(errno)); + return; + } + addr.sin_family = AF_INET; + addr.sin_port = htons(PPTP_PORT); + + opt = conf_get_opt("pptp", "bind"); + if (opt) + addr.sin_addr.s_addr = inet_addr(opt); + else + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + setsockopt(serv.hnd.fd, SOL_SOCKET, SO_REUSEADDR, &serv.hnd.fd, 4); + if (bind (serv.hnd.fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) { + log_emerg("pptp: failed to bind socket: %s\n", strerror(errno)); + close(serv.hnd.fd); + return; + } + + if (listen (serv.hnd.fd, 100) < 0) { + log_emerg("pptp: failed to listen socket: %s\n", strerror(errno)); + close(serv.hnd.fd); + return; + } + + if (fcntl(serv.hnd.fd, F_SETFL, O_NONBLOCK)) { + log_emerg("pptp: failed to set nonblocking mode: %s\n", strerror(errno)); + close(serv.hnd.fd); + return; + } + + opt = conf_get_opt("pptp", "timeout"); + if (opt && atoi(opt) > 0) + conf_timeout = atoi(opt); + + opt = conf_get_opt("pptp", "echo-interval"); + if (opt && atoi(opt) >= 0) + conf_echo_interval = atoi(opt); + + 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; + + 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); +} + diff --git a/accel-pptpd/ctrl/pptp/pptp_prot.h b/accel-pptpd/ctrl/pptp/pptp_prot.h new file mode 100644 index 00000000..ee8cb341 --- /dev/null +++ b/accel-pptpd/ctrl/pptp/pptp_prot.h @@ -0,0 +1,299 @@ +#ifndef PPTP_PROT_H +#define PPTP_PROT_H + +#include + +#define PPTP_MAX_MTU 1436 + +#define hton8(x) (x) +#define ntoh8(x) (x) +#define hton16(x) htons(x) +#define ntoh16(x) ntohs(x) +#define hton32(x) htonl(x) +#define ntoh32(x) ntohl(x) + +/* PPTP magic numbers: ----------------------------------------- */ + +#define PPTP_MAGIC 0x1A2B3C4D /* Magic cookie for PPTP datagrams */ +#define PPTP_PORT 1723 /* PPTP TCP port number */ +#define PPTP_PROTO 47 /* PPTP IP protocol number */ + +/* PPTP result codes:---------------------------------------- */ +#define PPTP_CONN_RES_SUCCESS 1 +#define PPTP_CONN_RES_GE 2 +#define PPTP_CONN_RES_EXISTS 3 +#define PPTP_CONN_RES_AUTH 4 +#define PPTP_CONN_RES_PROTOCOL 5 + +#define PPTP_CONN_STOP_OK 1 +#define PPTP_CONN_STOP_GE 2 + +#define PPTP_CALL_RES_OK 1 +#define PPTP_CALL_RES_GE 2 + +#define PPTP_GE_NOCONN 1 + +/* Control Connection Message Types: --------------------------- */ + +#define PPTP_MESSAGE_CONTROL 1 +#define PPTP_MESSAGE_MANAGE 2 + +/* Control Message Types: -------------------------------------- */ + +/* (Control Connection Management) */ +#define PPTP_START_CTRL_CONN_RQST 1 +#define PPTP_START_CTRL_CONN_RPLY 2 +#define PPTP_STOP_CTRL_CONN_RQST 3 +#define PPTP_STOP_CTRL_CONN_RPLY 4 +#define PPTP_ECHO_RQST 5 +#define PPTP_ECHO_RPLY 6 + +/* (Call Management) */ +#define PPTP_OUT_CALL_RQST 7 +#define PPTP_OUT_CALL_RPLY 8 +#define PPTP_IN_CALL_RQST 9 +#define PPTP_IN_CALL_RPLY 10 +#define PPTP_IN_CALL_CONNECT 11 +#define PPTP_CALL_CLEAR_RQST 12 +#define PPTP_CALL_CLEAR_NTFY 13 + +/* (Error Reporting) */ +#define PPTP_WAN_ERR_NTFY 14 + +/* (PPP Session Control) */ +#define PPTP_SET_LINK_INFO 15 + +/* PPTP version information: --------------------------------------*/ +#define PPTP_VERSION_STRING "1.00" +#define PPTP_VERSION 0x100 +#define PPTP_FIRMWARE_STRING "0.01" +#define PPTP_FIRMWARE_VERSION 0x001 + +#define PPTP_HOSTNAME "local" +#define PPTP_VENDOR "cananian" + +/* PPTP capabilities: ---------------------------------------------*/ + +/* (Framing capabilities for msg sender) */ +#define PPTP_FRAME_ASYNC 1 +#define PPTP_FRAME_SYNC 2 +#define PPTP_FRAME_ANY 3 + +/* (Bearer capabilities for msg sender) */ +#define PPTP_BEARER_ANALOG 1 +#define PPTP_BEARER_DIGITAL 2 +#define PPTP_BEARER_ANY 3 + +#define PPTP_RESULT_GENERAL_ERROR 2 + +/* (Reasons to close a connection) */ +#define PPTP_STOP_NONE 1 /* no good reason */ +#define PPTP_STOP_PROTOCOL 2 /* can't support peer's protocol version */ +#define PPTP_STOP_LOCAL_SHUTDOWN 3 /* requester is being shut down */ + +/* PPTP datagram structures (all data in network byte order): ----------*/ + +struct pptp_header +{ + uint16_t length; /* message length in octets, including header */ + uint16_t pptp_type; /* PPTP message type. 1 for control message. */ + uint32_t magic; /* this should be PPTP_MAGIC. */ + uint16_t ctrl_type; /* Control message type (0-15) */ + uint16_t reserved0; /* reserved. MUST BE ZERO. */ +}__attribute__((packed)); + +struct pptp_start_ctrl_conn /* for control message types 1 and 2 */ +{ + struct pptp_header header; + + uint16_t version; /* PPTP protocol version. = PPTP_VERSION */ + uint8_t result_code; /* these two fields should be zero on rqst msg*/ + uint8_t error_code; /* 0 unless result_code==2 (General Error) */ + uint32_t framing_cap; /* Framing capabilities */ + uint32_t bearer_cap; /* Bearer Capabilities */ + uint16_t max_channels; /* Maximum Channels (=0 for PNS, PAC ignores) */ + uint16_t firmware_rev; /* Firmware or Software Revision */ + uint8_t hostname[64]; /* Host Name (64 octets, zero terminated) */ + uint8_t vendor[64]; /* Vendor string (64 octets, zero term.) */ +}__attribute__((packed)); + +struct pptp_stop_ctrl_conn /* for control message types 3 and 4 */ +{ + struct pptp_header header; + + uint8_t reason_result; /* reason for rqst, result for rply */ + uint8_t error_code; /* MUST be 0, unless rply result==2 (general err)*/ + uint16_t reserved1; /* MUST be 0 */ +}__attribute__((packed)); + +struct pptp_echo_rqst /* for control message type 5 */ +{ + struct pptp_header header; + uint32_t identifier; /* arbitrary value set by sender which is used */ + /* to match up reply and request */ +}__attribute__((packed)); + +struct pptp_echo_rply /* for control message type 6 */ +{ + struct pptp_header header; + uint32_t identifier; /* should correspond to id of rqst */ + uint8_t result_code; + uint8_t error_code; /* =0, unless result_code==2 (general error) */ + uint16_t reserved1; /* MUST BE ZERO */ +}__attribute__((packed)); + +struct pptp_out_call_rqst /* for control message type 7 */ +{ + struct pptp_header header; + uint16_t call_id; /* Call ID (unique id used to multiplex data) */ + uint16_t call_sernum; /* Call Serial Number (used for logging) */ + uint32_t bps_min; /* Minimum BPS (lowest acceptable line speed) */ + uint32_t bps_max; /* Maximum BPS (highest acceptable line speed) */ + uint32_t bearer; /* Bearer type */ + uint32_t framing; /* Framing type */ + uint16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ + uint16_t delay; /* Packet Processing Delay (in 1/10 sec) */ + uint16_t phone_len; /* Phone Number Length (num. of valid digits) */ + uint16_t reserved1; /* MUST BE ZERO */ + uint8_t phone_num[64]; /* Phone Number (64 octets, null term.) */ + uint8_t subaddress[64]; /* Subaddress (64 octets, null term.) */ +}__attribute__((packed)); + +struct pptp_out_call_rply /* for control message type 8 */ +{ + struct pptp_header header; + uint16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ + uint16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ + uint8_t result_code; /* Result Code (1 is no errors) */ + uint8_t error_code; /* Error Code (=0 unless result_code==2) */ + uint16_t cause_code; /* Cause Code (addt'l failure information) */ + uint32_t speed; /* Connect Speed (in BPS) */ + uint16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ + uint16_t delay; /* Packet Processing Delay (in 1/10 sec) */ + uint32_t channel; /* Physical Channel ID (for logging) */ +}__attribute__((packed)); + +struct pptp_in_call_rqst /* for control message type 9 */ +{ + struct pptp_header header; + uint16_t call_id; /* Call ID (unique id used to multiplex data) */ + uint16_t call_sernum; /* Call Serial Number (used for logging) */ + uint32_t bearer; /* Bearer type */ + uint32_t channel; /* Physical Channel ID (for logging) */ + uint16_t dialed_len; /* Dialed Number Length (# of valid digits) */ + uint16_t dialing_len; /* Dialing Number Length (# of valid digits) */ + uint8_t dialed_num[64]; /* Dialed Number (64 octets, zero term.) */ + uint8_t dialing_num[64]; /* Dialing Number (64 octets, zero term.) */ + uint8_t subaddress[64]; /* Subaddress (64 octets, zero term.) */ +}__attribute__((packed)); + +struct pptp_in_call_rply /* for control message type 10 */ +{ + struct pptp_header header; + uint16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ + uint16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ + uint8_t result_code; /* Result Code (1 is no errors) */ + uint8_t error_code; /* Error Code (=0 unless result_code==2) */ + uint16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ + uint16_t delay; /* Packet Processing Delay (in 1/10 sec) */ + uint16_t reserved1; /* MUST BE ZERO */ +}__attribute__((packed)); + +struct pptp_in_call_connect /* for control message type 11 */ +{ + struct pptp_header header; + uint16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ + uint16_t reserved1; /* MUST BE ZERO */ + uint32_t speed; /* Connect Speed (in BPS) */ + uint16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ + uint16_t delay; /* Packet Processing Delay (in 1/10 sec) */ + uint32_t framing; /* Framing type */ +}__attribute__((packed)); + +struct pptp_call_clear_rqst /* for control message type 12 */ +{ + struct pptp_header header; + uint16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ + uint16_t reserved1; /* MUST BE ZERO */ +}__attribute__((packed)); + +struct pptp_call_clear_ntfy /* for control message type 13 */ +{ + struct pptp_header header; + uint16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ + uint8_t result_code; /* Result Code */ + uint8_t error_code; /* Error Code (=0 unless result_code==2) */ + uint16_t cause_code; /* Cause Code (for ISDN, is Q.931 cause code) */ + uint16_t reserved1; /* MUST BE ZERO */ + uint8_t call_stats[128]; /* Call Statistics: 128 octets, ascii, 0-term */ +}__attribute__((packed)); + +struct pptp_wan_err_ntfy /* for control message type 14 */ +{ + struct pptp_header header; + uint16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ + uint16_t reserved1; /* MUST BE ZERO */ + uint32_t crc_errors; /* CRC errors */ + uint32_t frame_errors; /* Framing errors */ + uint32_t hard_errors; /* Hardware overruns */ + uint32_t buff_errors; /* Buffer overruns */ + uint32_t time_errors; /* Time-out errors */ + uint32_t align_errors; /* Alignment errors */ +}__attribute__((packed)); + +struct pptp_set_link_info /* for control message type 15 */ +{ + struct pptp_header header; + uint16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst) */ + uint16_t reserved1; /* MUST BE ZERO */ + uint32_t send_accm; /* Send ACCM (for PPP packets; default 0xFFFFFFFF)*/ + uint32_t recv_accm; /* Receive ACCM (for PPP pack.;default 0xFFFFFFFF)*/ +}__attribute__((packed)); + +/* helpful #defines: -------------------------------------------- */ +#define pptp_isvalid_ctrl(header, type, length) \ + (!( ( ntoh16(((struct pptp_header *)header)->length) < (length) ) || \ + ( ntoh16(((struct pptp_header *)header)->pptp_type) !=(type) ) || \ + ( ntoh32(((struct pptp_header *)header)->magic) !=PPTP_MAGIC) || \ + ( ntoh16(((struct pptp_header *)header)->ctrl_type) > PPTP_SET_LINK_INFO) || \ + ( ntoh16(((struct pptp_header *)header)->reserved0) !=0 ) )) + +#define PPTP_HEADER_CTRL(type) \ +{ hton16(PPTP_CTRL_SIZE(type)), \ + hton16(PPTP_MESSAGE_CONTROL), \ + hton32(PPTP_MAGIC), \ + hton16(type), 0 } + +#define PPTP_CTRL_SIZE(type) ( \ +(type==PPTP_START_CTRL_CONN_RQST)?sizeof(struct pptp_start_ctrl_conn): \ +(type==PPTP_START_CTRL_CONN_RPLY)?sizeof(struct pptp_start_ctrl_conn): \ +(type==PPTP_STOP_CTRL_CONN_RQST )?sizeof(struct pptp_stop_ctrl_conn): \ +(type==PPTP_STOP_CTRL_CONN_RPLY )?sizeof(struct pptp_stop_ctrl_conn): \ +(type==PPTP_ECHO_RQST )?sizeof(struct pptp_echo_rqst): \ +(type==PPTP_ECHO_RPLY )?sizeof(struct pptp_echo_rply): \ +(type==PPTP_OUT_CALL_RQST )?sizeof(struct pptp_out_call_rqst): \ +(type==PPTP_OUT_CALL_RPLY )?sizeof(struct pptp_out_call_rply): \ +(type==PPTP_IN_CALL_RQST )?sizeof(struct pptp_in_call_rqst): \ +(type==PPTP_IN_CALL_RPLY )?sizeof(struct pptp_in_call_rply): \ +(type==PPTP_IN_CALL_CONNECT )?sizeof(struct pptp_in_call_connect): \ +(type==PPTP_CALL_CLEAR_RQST )?sizeof(struct pptp_call_clear_rqst): \ +(type==PPTP_CALL_CLEAR_NTFY )?sizeof(struct pptp_call_clear_ntfy): \ +(type==PPTP_WAN_ERR_NTFY )?sizeof(struct pptp_wan_err_ntfy): \ +(type==PPTP_SET_LINK_INFO )?sizeof(struct pptp_set_link_info): \ +0) +#define max(a,b) (((a)>(b))?(a):(b)) +#define PPTP_CTRL_SIZE_MAX ( \ +max(sizeof(struct pptp_start_ctrl_conn), \ +max(sizeof(struct pptp_echo_rqst), \ +max(sizeof(struct pptp_echo_rply), \ +max(sizeof(struct pptp_out_call_rqst), \ +max(sizeof(struct pptp_out_call_rply), \ +max(sizeof(struct pptp_in_call_rqst), \ +max(sizeof(struct pptp_in_call_rply), \ +max(sizeof(struct pptp_in_call_connect), \ +max(sizeof(struct pptp_call_clear_rqst), \ +max(sizeof(struct pptp_call_clear_ntfy), \ +max(sizeof(struct pptp_wan_err_ntfy), \ +max(sizeof(struct pptp_set_link_info), 0))))))))))))) + +#endif diff --git a/accel-pptpd/ctrl/pptp_prot.h b/accel-pptpd/ctrl/pptp_prot.h deleted file mode 100644 index ee8cb341..00000000 --- a/accel-pptpd/ctrl/pptp_prot.h +++ /dev/null @@ -1,299 +0,0 @@ -#ifndef PPTP_PROT_H -#define PPTP_PROT_H - -#include - -#define PPTP_MAX_MTU 1436 - -#define hton8(x) (x) -#define ntoh8(x) (x) -#define hton16(x) htons(x) -#define ntoh16(x) ntohs(x) -#define hton32(x) htonl(x) -#define ntoh32(x) ntohl(x) - -/* PPTP magic numbers: ----------------------------------------- */ - -#define PPTP_MAGIC 0x1A2B3C4D /* Magic cookie for PPTP datagrams */ -#define PPTP_PORT 1723 /* PPTP TCP port number */ -#define PPTP_PROTO 47 /* PPTP IP protocol number */ - -/* PPTP result codes:---------------------------------------- */ -#define PPTP_CONN_RES_SUCCESS 1 -#define PPTP_CONN_RES_GE 2 -#define PPTP_CONN_RES_EXISTS 3 -#define PPTP_CONN_RES_AUTH 4 -#define PPTP_CONN_RES_PROTOCOL 5 - -#define PPTP_CONN_STOP_OK 1 -#define PPTP_CONN_STOP_GE 2 - -#define PPTP_CALL_RES_OK 1 -#define PPTP_CALL_RES_GE 2 - -#define PPTP_GE_NOCONN 1 - -/* Control Connection Message Types: --------------------------- */ - -#define PPTP_MESSAGE_CONTROL 1 -#define PPTP_MESSAGE_MANAGE 2 - -/* Control Message Types: -------------------------------------- */ - -/* (Control Connection Management) */ -#define PPTP_START_CTRL_CONN_RQST 1 -#define PPTP_START_CTRL_CONN_RPLY 2 -#define PPTP_STOP_CTRL_CONN_RQST 3 -#define PPTP_STOP_CTRL_CONN_RPLY 4 -#define PPTP_ECHO_RQST 5 -#define PPTP_ECHO_RPLY 6 - -/* (Call Management) */ -#define PPTP_OUT_CALL_RQST 7 -#define PPTP_OUT_CALL_RPLY 8 -#define PPTP_IN_CALL_RQST 9 -#define PPTP_IN_CALL_RPLY 10 -#define PPTP_IN_CALL_CONNECT 11 -#define PPTP_CALL_CLEAR_RQST 12 -#define PPTP_CALL_CLEAR_NTFY 13 - -/* (Error Reporting) */ -#define PPTP_WAN_ERR_NTFY 14 - -/* (PPP Session Control) */ -#define PPTP_SET_LINK_INFO 15 - -/* PPTP version information: --------------------------------------*/ -#define PPTP_VERSION_STRING "1.00" -#define PPTP_VERSION 0x100 -#define PPTP_FIRMWARE_STRING "0.01" -#define PPTP_FIRMWARE_VERSION 0x001 - -#define PPTP_HOSTNAME "local" -#define PPTP_VENDOR "cananian" - -/* PPTP capabilities: ---------------------------------------------*/ - -/* (Framing capabilities for msg sender) */ -#define PPTP_FRAME_ASYNC 1 -#define PPTP_FRAME_SYNC 2 -#define PPTP_FRAME_ANY 3 - -/* (Bearer capabilities for msg sender) */ -#define PPTP_BEARER_ANALOG 1 -#define PPTP_BEARER_DIGITAL 2 -#define PPTP_BEARER_ANY 3 - -#define PPTP_RESULT_GENERAL_ERROR 2 - -/* (Reasons to close a connection) */ -#define PPTP_STOP_NONE 1 /* no good reason */ -#define PPTP_STOP_PROTOCOL 2 /* can't support peer's protocol version */ -#define PPTP_STOP_LOCAL_SHUTDOWN 3 /* requester is being shut down */ - -/* PPTP datagram structures (all data in network byte order): ----------*/ - -struct pptp_header -{ - uint16_t length; /* message length in octets, including header */ - uint16_t pptp_type; /* PPTP message type. 1 for control message. */ - uint32_t magic; /* this should be PPTP_MAGIC. */ - uint16_t ctrl_type; /* Control message type (0-15) */ - uint16_t reserved0; /* reserved. MUST BE ZERO. */ -}__attribute__((packed)); - -struct pptp_start_ctrl_conn /* for control message types 1 and 2 */ -{ - struct pptp_header header; - - uint16_t version; /* PPTP protocol version. = PPTP_VERSION */ - uint8_t result_code; /* these two fields should be zero on rqst msg*/ - uint8_t error_code; /* 0 unless result_code==2 (General Error) */ - uint32_t framing_cap; /* Framing capabilities */ - uint32_t bearer_cap; /* Bearer Capabilities */ - uint16_t max_channels; /* Maximum Channels (=0 for PNS, PAC ignores) */ - uint16_t firmware_rev; /* Firmware or Software Revision */ - uint8_t hostname[64]; /* Host Name (64 octets, zero terminated) */ - uint8_t vendor[64]; /* Vendor string (64 octets, zero term.) */ -}__attribute__((packed)); - -struct pptp_stop_ctrl_conn /* for control message types 3 and 4 */ -{ - struct pptp_header header; - - uint8_t reason_result; /* reason for rqst, result for rply */ - uint8_t error_code; /* MUST be 0, unless rply result==2 (general err)*/ - uint16_t reserved1; /* MUST be 0 */ -}__attribute__((packed)); - -struct pptp_echo_rqst /* for control message type 5 */ -{ - struct pptp_header header; - uint32_t identifier; /* arbitrary value set by sender which is used */ - /* to match up reply and request */ -}__attribute__((packed)); - -struct pptp_echo_rply /* for control message type 6 */ -{ - struct pptp_header header; - uint32_t identifier; /* should correspond to id of rqst */ - uint8_t result_code; - uint8_t error_code; /* =0, unless result_code==2 (general error) */ - uint16_t reserved1; /* MUST BE ZERO */ -}__attribute__((packed)); - -struct pptp_out_call_rqst /* for control message type 7 */ -{ - struct pptp_header header; - uint16_t call_id; /* Call ID (unique id used to multiplex data) */ - uint16_t call_sernum; /* Call Serial Number (used for logging) */ - uint32_t bps_min; /* Minimum BPS (lowest acceptable line speed) */ - uint32_t bps_max; /* Maximum BPS (highest acceptable line speed) */ - uint32_t bearer; /* Bearer type */ - uint32_t framing; /* Framing type */ - uint16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ - uint16_t delay; /* Packet Processing Delay (in 1/10 sec) */ - uint16_t phone_len; /* Phone Number Length (num. of valid digits) */ - uint16_t reserved1; /* MUST BE ZERO */ - uint8_t phone_num[64]; /* Phone Number (64 octets, null term.) */ - uint8_t subaddress[64]; /* Subaddress (64 octets, null term.) */ -}__attribute__((packed)); - -struct pptp_out_call_rply /* for control message type 8 */ -{ - struct pptp_header header; - uint16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ - uint16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ - uint8_t result_code; /* Result Code (1 is no errors) */ - uint8_t error_code; /* Error Code (=0 unless result_code==2) */ - uint16_t cause_code; /* Cause Code (addt'l failure information) */ - uint32_t speed; /* Connect Speed (in BPS) */ - uint16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ - uint16_t delay; /* Packet Processing Delay (in 1/10 sec) */ - uint32_t channel; /* Physical Channel ID (for logging) */ -}__attribute__((packed)); - -struct pptp_in_call_rqst /* for control message type 9 */ -{ - struct pptp_header header; - uint16_t call_id; /* Call ID (unique id used to multiplex data) */ - uint16_t call_sernum; /* Call Serial Number (used for logging) */ - uint32_t bearer; /* Bearer type */ - uint32_t channel; /* Physical Channel ID (for logging) */ - uint16_t dialed_len; /* Dialed Number Length (# of valid digits) */ - uint16_t dialing_len; /* Dialing Number Length (# of valid digits) */ - uint8_t dialed_num[64]; /* Dialed Number (64 octets, zero term.) */ - uint8_t dialing_num[64]; /* Dialing Number (64 octets, zero term.) */ - uint8_t subaddress[64]; /* Subaddress (64 octets, zero term.) */ -}__attribute__((packed)); - -struct pptp_in_call_rply /* for control message type 10 */ -{ - struct pptp_header header; - uint16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ - uint16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ - uint8_t result_code; /* Result Code (1 is no errors) */ - uint8_t error_code; /* Error Code (=0 unless result_code==2) */ - uint16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ - uint16_t delay; /* Packet Processing Delay (in 1/10 sec) */ - uint16_t reserved1; /* MUST BE ZERO */ -}__attribute__((packed)); - -struct pptp_in_call_connect /* for control message type 11 */ -{ - struct pptp_header header; - uint16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ - uint16_t reserved1; /* MUST BE ZERO */ - uint32_t speed; /* Connect Speed (in BPS) */ - uint16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ - uint16_t delay; /* Packet Processing Delay (in 1/10 sec) */ - uint32_t framing; /* Framing type */ -}__attribute__((packed)); - -struct pptp_call_clear_rqst /* for control message type 12 */ -{ - struct pptp_header header; - uint16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ - uint16_t reserved1; /* MUST BE ZERO */ -}__attribute__((packed)); - -struct pptp_call_clear_ntfy /* for control message type 13 */ -{ - struct pptp_header header; - uint16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ - uint8_t result_code; /* Result Code */ - uint8_t error_code; /* Error Code (=0 unless result_code==2) */ - uint16_t cause_code; /* Cause Code (for ISDN, is Q.931 cause code) */ - uint16_t reserved1; /* MUST BE ZERO */ - uint8_t call_stats[128]; /* Call Statistics: 128 octets, ascii, 0-term */ -}__attribute__((packed)); - -struct pptp_wan_err_ntfy /* for control message type 14 */ -{ - struct pptp_header header; - uint16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ - uint16_t reserved1; /* MUST BE ZERO */ - uint32_t crc_errors; /* CRC errors */ - uint32_t frame_errors; /* Framing errors */ - uint32_t hard_errors; /* Hardware overruns */ - uint32_t buff_errors; /* Buffer overruns */ - uint32_t time_errors; /* Time-out errors */ - uint32_t align_errors; /* Alignment errors */ -}__attribute__((packed)); - -struct pptp_set_link_info /* for control message type 15 */ -{ - struct pptp_header header; - uint16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst) */ - uint16_t reserved1; /* MUST BE ZERO */ - uint32_t send_accm; /* Send ACCM (for PPP packets; default 0xFFFFFFFF)*/ - uint32_t recv_accm; /* Receive ACCM (for PPP pack.;default 0xFFFFFFFF)*/ -}__attribute__((packed)); - -/* helpful #defines: -------------------------------------------- */ -#define pptp_isvalid_ctrl(header, type, length) \ - (!( ( ntoh16(((struct pptp_header *)header)->length) < (length) ) || \ - ( ntoh16(((struct pptp_header *)header)->pptp_type) !=(type) ) || \ - ( ntoh32(((struct pptp_header *)header)->magic) !=PPTP_MAGIC) || \ - ( ntoh16(((struct pptp_header *)header)->ctrl_type) > PPTP_SET_LINK_INFO) || \ - ( ntoh16(((struct pptp_header *)header)->reserved0) !=0 ) )) - -#define PPTP_HEADER_CTRL(type) \ -{ hton16(PPTP_CTRL_SIZE(type)), \ - hton16(PPTP_MESSAGE_CONTROL), \ - hton32(PPTP_MAGIC), \ - hton16(type), 0 } - -#define PPTP_CTRL_SIZE(type) ( \ -(type==PPTP_START_CTRL_CONN_RQST)?sizeof(struct pptp_start_ctrl_conn): \ -(type==PPTP_START_CTRL_CONN_RPLY)?sizeof(struct pptp_start_ctrl_conn): \ -(type==PPTP_STOP_CTRL_CONN_RQST )?sizeof(struct pptp_stop_ctrl_conn): \ -(type==PPTP_STOP_CTRL_CONN_RPLY )?sizeof(struct pptp_stop_ctrl_conn): \ -(type==PPTP_ECHO_RQST )?sizeof(struct pptp_echo_rqst): \ -(type==PPTP_ECHO_RPLY )?sizeof(struct pptp_echo_rply): \ -(type==PPTP_OUT_CALL_RQST )?sizeof(struct pptp_out_call_rqst): \ -(type==PPTP_OUT_CALL_RPLY )?sizeof(struct pptp_out_call_rply): \ -(type==PPTP_IN_CALL_RQST )?sizeof(struct pptp_in_call_rqst): \ -(type==PPTP_IN_CALL_RPLY )?sizeof(struct pptp_in_call_rply): \ -(type==PPTP_IN_CALL_CONNECT )?sizeof(struct pptp_in_call_connect): \ -(type==PPTP_CALL_CLEAR_RQST )?sizeof(struct pptp_call_clear_rqst): \ -(type==PPTP_CALL_CLEAR_NTFY )?sizeof(struct pptp_call_clear_ntfy): \ -(type==PPTP_WAN_ERR_NTFY )?sizeof(struct pptp_wan_err_ntfy): \ -(type==PPTP_SET_LINK_INFO )?sizeof(struct pptp_set_link_info): \ -0) -#define max(a,b) (((a)>(b))?(a):(b)) -#define PPTP_CTRL_SIZE_MAX ( \ -max(sizeof(struct pptp_start_ctrl_conn), \ -max(sizeof(struct pptp_echo_rqst), \ -max(sizeof(struct pptp_echo_rply), \ -max(sizeof(struct pptp_out_call_rqst), \ -max(sizeof(struct pptp_out_call_rply), \ -max(sizeof(struct pptp_in_call_rqst), \ -max(sizeof(struct pptp_in_call_rply), \ -max(sizeof(struct pptp_in_call_connect), \ -max(sizeof(struct pptp_call_clear_rqst), \ -max(sizeof(struct pptp_call_clear_ntfy), \ -max(sizeof(struct pptp_wan_err_ntfy), \ -max(sizeof(struct pptp_set_link_info), 0))))))))))))) - -#endif diff --git a/accel-pptpd/radius/CMakeLists.txt b/accel-pptpd/radius/CMakeLists.txt index b82512e9..6872ee6b 100644 --- a/accel-pptpd/radius/CMakeLists.txt +++ b/accel-pptpd/radius/CMakeLists.txt @@ -8,7 +8,7 @@ SET(sources dm_coa.c ) -ADD_DEFINITIONS(-DDICT_PATH="${CMAKE_INSTALL_PREFIX}/usr/share/accel-pptp/dictionary") +ADD_DEFINITIONS(-DDICTIONARY="${CMAKE_INSTALL_PREFIX}/usr/share/accel-pptp/radius/dictionary") ADD_LIBRARY(radius SHARED ${sources}) @@ -16,5 +16,5 @@ INSTALL(TARGETS radius LIBRARY DESTINATION usr/lib/accel-pptp ) FILE(GLOB dict "${CMAKE_CURRENT_SOURCE_DIR}/dict/*") -INSTALL(FILES ${dict} DESTINATION usr/share/accel-pptp) +INSTALL(FILES ${dict} DESTINATION usr/share/accel-pptp/radius) diff --git a/accel-pptpd/radius/acct.c b/accel-pptpd/radius/acct.c index a8346edd..d855d120 100644 --- a/accel-pptpd/radius/acct.c +++ b/accel-pptpd/radius/acct.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include diff --git a/accel-pptpd/radius/dict.c b/accel-pptpd/radius/dict.c index 54cf895e..0d63a838 100644 --- a/accel-pptpd/radius/dict.c +++ b/accel-pptpd/radius/dict.c @@ -79,7 +79,7 @@ static int dict_load(const char *fname) f = fopen(fname, "r"); if (!f) { - log_error("radius: open dictioanary '%s': %s\n", fname, strerror(errno)); + log_emerg("radius: open dictioanary '%s': %s\n", fname, strerror(errno)); return -1; } @@ -94,7 +94,7 @@ static int dict_load(const char *fname) if (!strcmp(buf, "BEGIN-VENDOR")) { vendor = rad_dict_find_vendor_name(ptr[0]); if (!vendor) { - log_error("radius:%s:%i: vendor not found\n", fname, n); + log_emerg("radius:%s:%i: vendor not found\n", fname, n); goto out_err; } items = &vendor->items; @@ -156,13 +156,13 @@ static int dict_load(const char *fname) else if (!strcmp(ptr[2], "octets")) attr->type = ATTR_TYPE_OCTETS; else { - log_error("radius:%s:%i: unknown attribute type\n", fname, n); + log_emerg("radius:%s:%i: unknown attribute type\n", fname, n); goto out_err; } } else if (!strcmp(buf, "VALUE")) { attr = find_attr(items, ptr[0]); if (!attr) { - log_error("radius:%s:%i: unknown attribute\n", fname, n); + log_emerg("radius:%s:%i: unknown attribute\n", fname, n); goto out_err; } val = malloc(sizeof(*val)); @@ -200,7 +200,7 @@ static int dict_load(const char *fname) return 0; out_err_syntax: - log_error("radius:%s:%i: syntaxis error\n", fname, n); + log_emerg("radius:%s:%i: syntaxis error\n", fname, n); out_err: fclose(f); return -1; diff --git a/accel-pptpd/radius/radius.c b/accel-pptpd/radius/radius.c index 9f5c7ffc..817071e9 100644 --- a/accel-pptpd/radius/radius.c +++ b/accel-pptpd/radius/radius.c @@ -309,7 +309,7 @@ static int parse_server(const char *opt, char **name, int *port, char **secret) static void __init radius_init(void) { char *opt; - char *dict = DICT_PATH; + char *dict = DICTIONARY; rpd_pool = mempool_create(sizeof(struct radius_pd_t)); -- cgit v1.2.3