diff options
-rw-r--r-- | accel-pppd/accel-ppp.conf | 2 | ||||
-rw-r--r-- | accel-pppd/accel-ppp.conf.5 | 18 | ||||
-rw-r--r-- | accel-pppd/ctrl/l2tp/l2tp.c | 113 | ||||
-rw-r--r-- | accel-pppd/ctrl/l2tp/l2tp.h | 5 | ||||
-rw-r--r-- | accel-pppd/ctrl/l2tp/packet.c | 5 |
5 files changed, 142 insertions, 1 deletions
diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf index 38b0fa8..69f33b3 100644 --- a/accel-pppd/accel-ppp.conf +++ b/accel-pppd/accel-ppp.conf @@ -112,6 +112,8 @@ verbose=1 #host-name=accel-ppp #dir300_quirk=0 #secret= +#dataseq=allow +#reorder-timeout=0 verbose=1 [dns] diff --git a/accel-pppd/accel-ppp.conf.5 b/accel-pppd/accel-ppp.conf.5 index 2d585ba..fd9db87 100644 --- a/accel-pppd/accel-ppp.conf.5 +++ b/accel-pppd/accel-ppp.conf.5 @@ -492,6 +492,24 @@ If this option is given and is greater than 0, then attributes sent in L2TP packets will be hidden (for AVPs that support it). .TP +.BI "dataseq=" deny|allow|prefer|require +Specify data sequencing negotiation algorithm: +.br +.B deny +- don't send data packets with sequence numbers +.br +.B allow +- send data packets with sequence numbers if peer have requested so only +.br +.B prefer +- send data packets with sequence numbers and enable same for peer +.br +.B require +- send data packets with sequence numbers and enforce same for peer +.TP +.BI "reorder-timeout=" ms +Specifies timeout (in milliseconds) to wait for out-of-order packets. If 0, don't try to reorder. +.TP .BI "use-ephemeral-ports=" 0|1 Specifies if an arbitrary source port is used when replying to a tunnel establishment request. When this option is deactivated, the destination diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c index b4b20b7..e6fae4d 100644 --- a/accel-pppd/ctrl/l2tp/l2tp.c +++ b/accel-pppd/ctrl/l2tp/l2tp.c @@ -65,6 +65,8 @@ static const char *conf_host_name = "accel-ppp"; static const char *conf_secret = NULL; static size_t conf_secret_len = 0; static int conf_mppe = MPPE_UNSET; +static int conf_dataseq = L2TP_DATASEQ_ALLOW; +static int conf_reorder_timeout = 0; static unsigned int stat_active; static unsigned int stat_starting; @@ -85,6 +87,9 @@ struct l2tp_sess_t int state1; uint16_t lns_mode:1; uint16_t hide_avps:1; + uint16_t send_seq:1; + uint16_t recv_seq:1; + int reorder_timeout; struct triton_context_t sctx; struct triton_timer_t timeout_timer; @@ -870,6 +875,10 @@ static struct l2tp_sess_t *l2tp_tunnel_alloc_session(struct l2tp_conn_t *conn) sess->state1 = STATE_CLOSE; sess->lns_mode = conn->lns_mode; sess->hide_avps = conn->hide_avps; + sess->send_seq = (conf_dataseq == L2TP_DATASEQ_PREFER) || + (conf_dataseq == L2TP_DATASEQ_REQUIRE); + sess->recv_seq = (conf_dataseq == L2TP_DATASEQ_REQUIRE); + sess->reorder_timeout = conf_reorder_timeout; sess->sctx.before_switch = log_switch; sess->sctx.close = l2tp_sess_close; @@ -1209,6 +1218,32 @@ static int l2tp_session_connect(struct l2tp_sess_t *sess) goto out_err; } + flg = 1; + if (sess->send_seq && + setsockopt(sess->ppp.fd, SOL_PPPOL2TP, PPPOL2TP_SO_SENDSEQ, + &flg, sizeof(flg))) { + log_session(log_error, sess, "impossible to connect session:" + " setsockopt(PPPOL2TP_SO_SENDSEQ) failed: %s\n", + strerror(errno)); + goto out_err; + } + if (sess->recv_seq && + setsockopt(sess->ppp.fd, SOL_PPPOL2TP, PPPOL2TP_SO_RECVSEQ, + &flg, sizeof(flg))) { + log_session(log_error, sess, "impossible to connect session:" + " setsockopt(PPPOL2TP_SO_RECVSEQ) failed: %s\n", + strerror(errno)); + goto out_err; + } + if (sess->reorder_timeout && + setsockopt(sess->ppp.fd, SOL_PPPOL2TP, PPPOL2TP_SO_REORDERTO, + &sess->reorder_timeout, sizeof(sess->reorder_timeout))) { + log_session(log_error, sess, "impossible to connect session:" + " setsockopt(PPPOL2TP_REORDERTO) failed: %s\n", + strerror(errno)); + goto out_err; + } + u_inet_ntoa(conn->peer_addr.sin_addr.s_addr, addr); peer_port = ntohs(conn->peer_addr.sin_port); if (_asprintf(&sess->ppp.ses.chan_name, "%s:%i session %i", @@ -1799,6 +1834,12 @@ static int l2tp_send_ICCN(struct l2tp_sess_t *sess) " adding data to packet failed\n"); goto out_err; } + if (sess->send_seq && + l2tp_packet_add_octets(pack, Sequencing_Required, NULL, 0, 1) < 0) { + log_session(log_error, sess, "impossible to send ICCN:" + " adding data to packet failed\n"); + goto out_err; + } if (l2tp_session_send(sess, pack) < 0) { log_session(log_error, sess, "impossible to send ICCN:" @@ -1938,6 +1979,12 @@ static int l2tp_send_OCCN(struct l2tp_sess_t *sess) " adding data to packet failed\n"); goto out_err; } + if (sess->send_seq && + l2tp_packet_add_octets(pack, Sequencing_Required, NULL, 0, 1) < 0) { + log_session(log_error, sess, "impossible to send OCCN:" + " adding data to packet failed\n"); + goto out_err; + } if (l2tp_session_send(sess, pack) < 0) { log_session(log_error, sess, "impossible to send OCCN:" @@ -2638,6 +2685,9 @@ static int l2tp_recv_ICRP(struct l2tp_sess_t *sess, static int l2tp_recv_ICCN(struct l2tp_sess_t *sess, const struct l2tp_packet_t *pack) { + const struct l2tp_attr_t *unknown_attr = NULL; + const struct l2tp_attr_t *attr = NULL; + if (sess->state1 != STATE_WAIT_ICCN) { log_session(log_warn, sess, "discarding unexpected ICCN\n"); return 0; @@ -2645,6 +2695,49 @@ static int l2tp_recv_ICCN(struct l2tp_sess_t *sess, log_session(log_info2, sess, "handling ICCN\n"); + list_for_each_entry(attr, &pack->attrs, entry) { + switch (attr->attr->id) { + case Message_Type: + case Random_Vector: + case TX_Speed: + case Framing_Type: + case Init_Recv_LCP: + case Last_Sent_LCP: + case Last_Recv_LCP: + case Proxy_Authen_Type: + case Proxy_Authen_Name: + case Proxy_Authen_Challenge: + case Proxy_Authen_ID: + case Proxy_Authen_Response: + case Private_Group_ID: + case RX_Speed: + break; + case Sequencing_Required: + if (conf_dataseq != L2TP_DATASEQ_DENY) + sess->send_seq = 1; + break; + default: + if (attr->M) + unknown_attr = attr; + else + log_session(log_warn, sess, + "discarding unknown attribute type" + " %i in ICCN\n", attr->attr->id); + break; + } + } + + if (unknown_attr) { + log_session(log_error, sess, "impossible to handle ICCN:" + " unknown mandatory attribute type %i," + " disconnecting session\n", + unknown_attr->attr->id); + if (l2tp_session_disconnect(sess, 2, 8) < 0) + log_session(log_error, sess, + "session disconnection failed\n"); + return -1; + } + sess->state1 = STATE_ESTB; if (l2tp_session_connect(sess)) { @@ -2906,6 +2999,10 @@ static int l2tp_recv_OCCN(struct l2tp_sess_t *sess, case TX_Speed: case Framing_Type: break; + case Sequencing_Required: + if (conf_dataseq != L2TP_DATASEQ_DENY) + sess->send_seq = 1; + break; default: if (attr->M) unknown_attr = attr; @@ -3796,6 +3893,22 @@ static void load_config(void) if (opt && atoi(opt) >= 0) conf_hide_avps = atoi(opt) > 0; + opt = conf_get_opt("l2tp", "dataseq"); + if (opt) { + if (strcmp(opt, "deny") == 0) + conf_dataseq = L2TP_DATASEQ_DENY; + else if (strcmp(opt, "allow") == 0) + conf_dataseq = L2TP_DATASEQ_ALLOW; + else if (strcmp(opt, "prefer") == 0) + conf_dataseq = L2TP_DATASEQ_PREFER; + else if (strcmp(opt, "require") == 0) + conf_dataseq = L2TP_DATASEQ_REQUIRE; + } + + opt = conf_get_opt("l2tp", "reorder-timeout"); + if (opt && atoi(opt) >= 0) + conf_reorder_timeout = atoi(opt); + opt = conf_get_opt("l2tp", "avp_permissive"); if (opt && atoi(opt) >= 0) conf_avp_permissive = atoi(opt) > 0; diff --git a/accel-pppd/ctrl/l2tp/l2tp.h b/accel-pppd/ctrl/l2tp/l2tp.h index b816bc8..91844c6 100644 --- a/accel-pppd/ctrl/l2tp/l2tp.h +++ b/accel-pppd/ctrl/l2tp/l2tp.h @@ -18,6 +18,11 @@ #define L2TP_V2_PROTOCOL_VERSION ( 1 << 8 | 0 ) +#define L2TP_DATASEQ_ALLOW -1 +#define L2TP_DATASEQ_DENY 0 +#define L2TP_DATASEQ_PREFER 1 +#define L2TP_DATASEQ_REQUIRE 2 + typedef union { uint32_t uint32; diff --git a/accel-pppd/ctrl/l2tp/packet.c b/accel-pppd/ctrl/l2tp/packet.c index e4278a3..78e0789 100644 --- a/accel-pppd/ctrl/l2tp/packet.c +++ b/accel-pppd/ctrl/l2tp/packet.c @@ -868,7 +868,10 @@ int l2tp_packet_add_octets(struct l2tp_packet_t *pack, int id, const uint8_t *va if (!attr) return -1; - if (attr->H) { + if (size == 0) { + attr->length = size; + attr->val.octets = NULL; + } else if (attr->H) { if (pack->last_RV == NULL) if (l2tp_packet_add_random_vector(pack) < 0) goto err; |