summaryrefslogtreecommitdiff
path: root/accel-pppd/ctrl
diff options
context:
space:
mode:
authorKozlov Dmitry <xeb@mail.ru>2013-04-19 13:29:06 +0400
committerKozlov Dmitry <xeb@mail.ru>2013-04-19 13:29:06 +0400
commit65159a74bd8e234f24bff44c267c251a080e1f14 (patch)
tree19561f39824d52c953f0acea26e450bfb31f72bc /accel-pppd/ctrl
parentbff0ea1c99ff68ca6f1ab58dcdfa0054caf42fca (diff)
parentd3ad0e29c57c74c93db97f165bfa43024e180db3 (diff)
downloadaccel-ppp-65159a74bd8e234f24bff44c267c251a080e1f14.tar.gz
accel-ppp-65159a74bd8e234f24bff44c267c251a080e1f14.zip
Merge branch 'master' of ssh://git.code.sf.net/p/accel-ppp/code
Diffstat (limited to 'accel-pppd/ctrl')
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c2
-rw-r--r--accel-pppd/ctrl/l2tp/l2tp.c160
-rw-r--r--accel-pppd/ctrl/l2tp/l2tp.h11
-rw-r--r--accel-pppd/ctrl/l2tp/packet.c489
4 files changed, 566 insertions, 96 deletions
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index 116e83c..09bd887 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.c
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -816,6 +816,7 @@ static struct ipoe_session *ipoe_session_create_dhcpv4(struct ipoe_serv *serv, s
if (pack->client_id) {
ses->client_id = (struct dhcpv4_option *)ptr;
ses->client_id->len = pack->client_id->len;
+ ses->client_id->data = (uint8_t *)(ses->client_id + 1);
memcpy(ses->client_id->data, pack->client_id->data, pack->client_id->len);
ptr += sizeof(struct dhcpv4_option) + pack->client_id->len;
}
@@ -823,6 +824,7 @@ static struct ipoe_session *ipoe_session_create_dhcpv4(struct ipoe_serv *serv, s
if (pack->relay_agent) {
ses->relay_agent = (struct dhcpv4_option *)ptr;
ses->relay_agent->len = pack->relay_agent->len;
+ ses->relay_agent->data = (uint8_t *)(ses->relay_agent + 1);
memcpy(ses->relay_agent->data, pack->relay_agent->data, pack->relay_agent->len);
ptr += sizeof(struct dhcpv4_option) + pack->relay_agent->len;
if (dhcpv4_parse_opt82(ses->relay_agent, &ses->agent_circuit_id, &ses->agent_remote_id))
diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c
index 7c53e6e..19b90ab 100644
--- a/accel-pppd/ctrl/l2tp/l2tp.c
+++ b/accel-pppd/ctrl/l2tp/l2tp.c
@@ -49,6 +49,7 @@
#define STATE_CLOSE 0
int conf_verbose = 0;
+int conf_hide_avps = 0;
int conf_avp_permissive = 0;
static int conf_timeout = 60;
static int conf_rtimeout = 5;
@@ -57,6 +58,7 @@ static int conf_hello_interval = 60;
static int conf_dir300_quirk = 0;
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 unsigned int stat_active;
@@ -77,6 +79,7 @@ struct l2tp_sess_t
int state1;
uint16_t lns_mode:1;
+ uint16_t hide_avps:1;
struct triton_context_t sctx;
struct triton_timer_t timeout_timer;
@@ -100,6 +103,7 @@ struct l2tp_conn_t
uint16_t peer_tid;
uint32_t framing_cap;
uint16_t lns_mode:1;
+ uint16_t hide_avps:1;
uint16_t port_set:1;
uint16_t challenge_len;
uint8_t *challenge;
@@ -222,11 +226,10 @@ static int l2tp_tunnel_genchall(uint16_t chall_len,
struct l2tp_packet_t *pack)
{
void *ptr = NULL;
- size_t urandlen;
- ssize_t rdlen;
+ int err;
if (chall_len == 0
- || conf_secret == NULL || strlen(conf_secret) == 0) {
+ || conf_secret == NULL || conf_secret_len == 0) {
if (conn->challenge) {
_free(conn->challenge);
conn->challenge = NULL;
@@ -247,26 +250,18 @@ static int l2tp_tunnel_genchall(uint16_t chall_len,
conn->challenge_len = chall_len;
}
- for (urandlen = 0; urandlen < chall_len; urandlen += rdlen) {
- rdlen = read(urandom_fd, conn->challenge + urandlen,
- chall_len - urandlen);
- if (rdlen < 0) {
- if (errno == EINTR)
- rdlen = 0;
- else {
- log_tunnel(log_error, conn,
- "impossible to generate Challenge:"
- " reading from urandom failed: %s\n",
- strerror(errno));
- goto err;
- }
- } else if (rdlen == 0) {
+ if (u_randbuf(conn->challenge, chall_len, &err) < 0) {
+ if (err)
+ log_tunnel(log_error, conn,
+ "impossible to generate Challenge:"
+ " reading from urandom failed: %s\n",
+ strerror(err));
+ else
log_tunnel(log_error, conn,
"impossible to generate Challenge:"
" end of file reached while reading"
" from urandom\n");
- goto err;
- }
+ goto err;
}
if (l2tp_packet_add_octets(pack, Challenge, conn->challenge,
@@ -302,7 +297,7 @@ static int l2tp_tunnel_storechall(struct l2tp_conn_t *conn,
return 0;
}
- if (conf_secret == NULL || strlen(conf_secret) == 0) {
+ if (conf_secret == NULL || conf_secret_len == 0) {
log_tunnel(log_error, conn, "authentication required by peer,"
" but no secret has been set for this tunnel\n");
goto err;
@@ -340,21 +335,21 @@ static int l2tp_tunnel_genchallresp(uint8_t msgident,
uint8_t challresp[MD5_DIGEST_LENGTH];
if (conn->challenge == NULL) {
- if (conf_secret && strlen(conf_secret) > 0) {
+ if (conf_secret && conf_secret_len > 0) {
log_tunnel(log_warn, conn,
"no Challenge sent by peer\n");
}
return 0;
}
- if (conf_secret == NULL || strlen(conf_secret) == 0) {
+ if (conf_secret == NULL || conf_secret_len == 0) {
log_tunnel(log_error, conn,
"impossible to generate Challenge Response:"
" no secret set for this tunnel\n");
return -1;
}
- comp_chap_md5(challresp, msgident, conf_secret, strlen(conf_secret),
+ comp_chap_md5(challresp, msgident, conf_secret, conf_secret_len,
conn->challenge, conn->challenge_len);
if (l2tp_packet_add_octets(pack, Challenge_Response, challresp,
MD5_DIGEST_LENGTH, 1) < 0) {
@@ -373,7 +368,7 @@ static int l2tp_tunnel_checkchallresp(uint8_t msgident,
{
uint8_t challref[MD5_DIGEST_LENGTH];
- if (conf_secret == NULL || strlen(conf_secret) == 0) {
+ if (conf_secret == NULL || conf_secret_len == 0) {
if (challresp) {
log_tunnel(log_warn, conn,
"discarding unexpected Challenge Response"
@@ -400,7 +395,7 @@ static int l2tp_tunnel_checkchallresp(uint8_t msgident,
return -1;
}
- comp_chap_md5(challref, msgident, conf_secret, strlen(conf_secret),
+ comp_chap_md5(challref, msgident, conf_secret, conf_secret_len,
conn->challenge, conn->challenge_len);
if (memcmp(challref, challresp->val.octets, MD5_DIGEST_LENGTH) != 0) {
log_tunnel(log_error, conn, "impossible to authenticate peer:"
@@ -422,7 +417,8 @@ static int l2tp_send_StopCCN(struct l2tp_conn_t *conn,
res, err);
pack = l2tp_packet_alloc(2, Message_Type_Stop_Ctrl_Conn_Notify,
- &conn->peer_addr);
+ &conn->peer_addr, conn->hide_avps,
+ conf_secret, conf_secret_len);
if (pack == NULL) {
log_tunnel(log_error, conn, "impossible to send StopCCN:"
" packet allocation failed\n");
@@ -464,7 +460,8 @@ static int l2tp_send_CDN(struct l2tp_sess_t *sess, uint16_t res, uint16_t err)
res, err);
pack = l2tp_packet_alloc(2, Message_Type_Call_Disconnect_Notify,
- &sess->paren_conn->peer_addr);
+ &sess->paren_conn->peer_addr, sess->hide_avps,
+ conf_secret, conf_secret_len);
if (pack == NULL) {
log_session(log_error, sess, "impossible to send CDN:"
" packet allocation failed\n");
@@ -508,7 +505,8 @@ static int l2tp_tunnel_send_CDN(uint16_t sid, uint16_t peer_sid,
res, err);
pack = l2tp_packet_alloc(2, Message_Type_Call_Disconnect_Notify,
- &conn->peer_addr);
+ &conn->peer_addr, conn->hide_avps,
+ conf_secret, conf_secret_len);
if (pack == NULL) {
log_tunnel(log_error, conn, "impossible to send CDN:"
" packet allocation failed\n");
@@ -871,6 +869,7 @@ static struct l2tp_sess_t *l2tp_tunnel_alloc_session(struct l2tp_conn_t *conn)
sess->peer_sid = 0;
sess->state1 = STATE_CLOSE;
sess->lns_mode = conn->lns_mode;
+ sess->hide_avps = conn->hide_avps;
sess->sctx.before_switch = log_switch;
sess->sctx.close = l2tp_sess_close;
@@ -998,7 +997,8 @@ err:
static struct l2tp_conn_t *l2tp_tunnel_alloc(const struct sockaddr_in *peer,
const struct sockaddr_in *host,
uint32_t framing_cap,
- int lns_mode, int port_set)
+ int lns_mode, int port_set,
+ int hide_avps)
{
struct l2tp_conn_t *conn;
socklen_t hostaddrlen = sizeof(conn->host_addr);
@@ -1127,6 +1127,7 @@ static struct l2tp_conn_t *l2tp_tunnel_alloc(const struct sockaddr_in *peer,
conn->sess_count = 0;
conn->lns_mode = lns_mode;
conn->port_set = port_set;
+ conn->hide_avps = hide_avps;
return conn;
@@ -1466,7 +1467,7 @@ static int l2tp_send_ZLB(struct l2tp_conn_t *conn)
log_tunnel(log_debug, conn, "sending ZLB\n");
- pack = l2tp_packet_alloc(2, 0, &conn->peer_addr);
+ pack = l2tp_packet_alloc(2, 0, &conn->peer_addr, 0, NULL, 0);
if (!pack) {
log_tunnel(log_error, conn, "impossible to send ZLB:"
" packet allocation failed\n");
@@ -1489,7 +1490,8 @@ static void l2tp_send_HELLO(struct triton_timer_t *t)
log_tunnel(log_debug, conn, "sending HELLO\n");
- pack = l2tp_packet_alloc(2, Message_Type_Hello, &conn->peer_addr);
+ pack = l2tp_packet_alloc(2, Message_Type_Hello, &conn->peer_addr,
+ conn->hide_avps, conf_secret, conf_secret_len);
if (!pack) {
log_tunnel(log_error, conn, "impossible to send HELLO:"
" packet allocation failed\n");
@@ -1505,11 +1507,14 @@ static void l2tp_send_SCCRQ(void *peer_addr)
{
struct l2tp_conn_t *conn = l2tp_tunnel_self();
struct l2tp_packet_t *pack = NULL;
+ uint16_t chall_len;
+ int err;
log_tunnel(log_info2, conn, "sending SCCRQ\n");
pack = l2tp_packet_alloc(2, Message_Type_Start_Ctrl_Conn_Request,
- &conn->peer_addr);
+ &conn->peer_addr, conn->hide_avps,
+ conf_secret, conf_secret_len);
if (pack == NULL) {
log_tunnel(log_error, conn, "impossible to send SCCRQ:"
" packet allocation failed\n");
@@ -1545,7 +1550,19 @@ static void l2tp_send_SCCRQ(void *peer_addr)
goto pack_err;
}
- if (l2tp_tunnel_genchall(MD5_DIGEST_LENGTH, conn, pack) < 0) {
+ if (u_randbuf(&chall_len, sizeof(chall_len), &err) < 0) {
+ if (err)
+ log_tunnel(log_error, conn, "impossible to send SCCRQ:"
+ " reading from urandom failed: %s\n",
+ strerror(err));
+ else
+ log_tunnel(log_error, conn, "impossible to send SCCRQ:"
+ " end of file reached while reading"
+ " from urandom\n");
+ goto pack_err;
+ }
+ chall_len = (chall_len & 0x007F) + MD5_DIGEST_LENGTH;
+ if (l2tp_tunnel_genchall(chall_len, conn, pack) < 0) {
log_tunnel(log_error, conn, "impossible to send SCCRQ:"
" Challenge generation failed\n");
goto pack_err;
@@ -1570,11 +1587,14 @@ err:
static void l2tp_send_SCCRP(struct l2tp_conn_t *conn)
{
struct l2tp_packet_t *pack;
+ uint16_t chall_len;
+ int err;
log_tunnel(log_info2, conn, "sending SCCRP\n");
pack = l2tp_packet_alloc(2, Message_Type_Start_Ctrl_Conn_Reply,
- &conn->peer_addr);
+ &conn->peer_addr, conn->hide_avps,
+ conf_secret, conf_secret_len);
if (!pack) {
log_tunnel(log_error, conn, "impossible to send SCCRP:"
" packet allocation failed\n");
@@ -1616,7 +1636,20 @@ static void l2tp_send_SCCRP(struct l2tp_conn_t *conn)
" Challenge Response generation failed\n");
goto out_err;
}
- if (l2tp_tunnel_genchall(MD5_DIGEST_LENGTH, conn, pack) < 0) {
+
+ if (u_randbuf(&chall_len, sizeof(chall_len), &err) < 0) {
+ if (err)
+ log_tunnel(log_error, conn, "impossible to send SCCRP:"
+ " reading from urandom failed: %s\n",
+ strerror(err));
+ else
+ log_tunnel(log_error, conn, "impossible to send SCCRP:"
+ " end of file reached while reading"
+ " from urandom\n");
+ goto out_err;
+ }
+ chall_len = (chall_len & 0x007F) + MD5_DIGEST_LENGTH;
+ if (l2tp_tunnel_genchall(chall_len, conn, pack) < 0) {
log_tunnel(log_error, conn, "impossible to send SCCRP:"
" Challenge generation failed\n");
goto out_err;
@@ -1645,7 +1678,8 @@ static int l2tp_send_SCCCN(struct l2tp_conn_t *conn)
log_tunnel(log_info2, conn, "sending SCCCN\n");
pack = l2tp_packet_alloc(2, Message_Type_Start_Ctrl_Conn_Connected,
- &conn->peer_addr);
+ &conn->peer_addr, conn->hide_avps,
+ conf_secret, conf_secret_len);
if (pack == NULL) {
log_tunnel(log_error, conn, "impossible to send SCCCN:"
" packet allocation failed\n");
@@ -1681,7 +1715,8 @@ static int l2tp_send_ICRQ(struct l2tp_sess_t *sess)
log_session(log_info2, sess, "sending ICRQ\n");
pack = l2tp_packet_alloc(2, Message_Type_Incoming_Call_Request,
- &sess->paren_conn->peer_addr);
+ &sess->paren_conn->peer_addr, sess->hide_avps,
+ conf_secret, conf_secret_len);
if (pack == NULL) {
log_session(log_error, sess, "impossible to send ICRQ:"
" packet allocation failed\n");
@@ -1720,7 +1755,8 @@ static int l2tp_send_ICRP(struct l2tp_sess_t *sess)
log_session(log_info2, sess, "sending ICRP\n");
pack = l2tp_packet_alloc(2, Message_Type_Incoming_Call_Reply,
- &sess->paren_conn->peer_addr);
+ &sess->paren_conn->peer_addr, sess->hide_avps,
+ conf_secret, conf_secret_len);
if (!pack) {
log_session(log_error, sess, "impossible to send ICRP:"
" packet allocation failed\n");
@@ -1754,7 +1790,8 @@ static int l2tp_send_ICCN(struct l2tp_sess_t *sess)
log_session(log_info2, sess, "sending ICCN\n");
pack = l2tp_packet_alloc(2, Message_Type_Incoming_Call_Connected,
- &sess->paren_conn->peer_addr);
+ &sess->paren_conn->peer_addr, sess->hide_avps,
+ conf_secret, conf_secret_len);
if (pack == 0) {
log_session(log_error, sess, "impossible to send ICCN:"
" packet allocation failed\n");
@@ -1798,7 +1835,8 @@ static int l2tp_send_OCRQ(struct l2tp_sess_t *sess)
log_session(log_info2, sess, "sending OCRQ\n");
pack = l2tp_packet_alloc(2, Message_Type_Outgoing_Call_Request,
- &sess->paren_conn->peer_addr);
+ &sess->paren_conn->peer_addr, sess->hide_avps,
+ conf_secret, conf_secret_len);
if (!pack) {
log_session(log_error, sess, "impossible to send OCRQ:"
" packet allocation failed\n");
@@ -1862,7 +1900,8 @@ static int l2tp_send_OCRP(struct l2tp_sess_t *sess)
log_session(log_info2, sess, "sending OCRP\n");
pack = l2tp_packet_alloc(2, Message_Type_Outgoing_Call_Reply,
- &sess->paren_conn->peer_addr);
+ &sess->paren_conn->peer_addr, sess->hide_avps,
+ conf_secret, conf_secret_len);
if (pack == NULL) {
log_session(log_error, sess, "impossible to send OCRP:"
" packet allocation failed\n");
@@ -1896,7 +1935,8 @@ static int l2tp_send_OCCN(struct l2tp_sess_t *sess)
log_session(log_info2, sess, "sending OCCN\n");
pack = l2tp_packet_alloc(2, Message_Type_Outgoing_Call_Connected,
- &sess->paren_conn->peer_addr);
+ &sess->paren_conn->peer_addr, sess->hide_avps,
+ conf_secret, conf_secret_len);
if (pack == NULL) {
log_session(log_error, sess, "impossible to send OCCN:"
" packet allocation failed\n");
@@ -1962,6 +2002,8 @@ static int l2tp_recv_SCCRQ(const struct l2tp_serv_t *serv,
list_for_each_entry(attr, &pack->attrs, entry) {
switch (attr->attr->id) {
+ case Random_Vector:
+ break;
case Protocol_Version:
protocol_version = attr;
break;
@@ -2014,7 +2056,8 @@ static int l2tp_recv_SCCRQ(const struct l2tp_serv_t *serv,
host_addr.sin_port = 0;
conn = l2tp_tunnel_alloc(&pack->addr, &host_addr,
- framing_cap->val.uint32, 1, 1);
+ framing_cap->val.uint32, 1, 1,
+ conf_hide_avps);
if (conn == NULL) {
log_error("l2tp: impossible to handle SCCRQ from %s:"
" tunnel allocation failed\n", src_addr);
@@ -2079,6 +2122,7 @@ static int l2tp_recv_SCCRP(struct l2tp_conn_t *conn,
list_for_each_entry(attr, &pack->attrs, entry) {
switch (attr->attr->id) {
case Message_Type:
+ case Random_Vector:
case Host_Name:
case Bearer_Capabilities:
case Firmware_Revision:
@@ -2214,6 +2258,7 @@ static int l2tp_recv_SCCCN(struct l2tp_conn_t *conn,
list_for_each_entry(attr, &pack->attrs, entry) {
switch (attr->attr->id) {
case Message_Type:
+ case Random_Vector:
break;
case Challenge_Response:
challenge_resp = attr;
@@ -2312,6 +2357,7 @@ static int l2tp_recv_StopCCN(struct l2tp_conn_t *conn,
list_for_each_entry(attr, &pack->attrs, entry) {
switch(attr->attr->id) {
case Message_Type:
+ case Random_Vector:
break;
case Assigned_Tunnel_ID:
assigned_tid = attr;
@@ -2425,6 +2471,7 @@ static int l2tp_recv_ICRQ(struct l2tp_conn_t *conn,
assigned_sid = attr;
break;
case Message_Type:
+ case Random_Vector:
case Call_Serial_Number:
case Bearer_Type:
case Calling_Number:
@@ -2519,6 +2566,7 @@ static int l2tp_recv_ICRP(struct l2tp_sess_t *sess,
list_for_each_entry(attr, &pack->attrs, entry) {
switch(attr->attr->id) {
case Message_Type:
+ case Random_Vector:
break;
case Assigned_Session_ID:
assigned_sid = attr;
@@ -2676,6 +2724,7 @@ static int l2tp_recv_OCRQ(struct l2tp_conn_t *conn,
list_for_each_entry(attr, &pack->attrs, entry) {
switch (attr->attr->id) {
case Message_Type:
+ case Random_Vector:
case Call_Serial_Number:
case Minimum_BPS:
case Maximum_BPS:
@@ -2775,6 +2824,7 @@ static int l2tp_recv_OCRP(struct l2tp_sess_t *sess,
list_for_each_entry(attr, &pack->attrs, entry) {
switch(attr->attr->id) {
case Message_Type:
+ case Random_Vector:
break;
case Assigned_Session_ID:
assigned_sid = attr;
@@ -2838,6 +2888,7 @@ static int l2tp_recv_OCCN(struct l2tp_sess_t *sess,
list_for_each_entry(attr, &pack->attrs, entry) {
switch (attr->attr->id) {
case Message_Type:
+ case Random_Vector:
case TX_Speed:
case Framing_Type:
break;
@@ -2902,6 +2953,7 @@ static int l2tp_recv_CDN(struct l2tp_sess_t *sess,
list_for_each_entry(attr, &pack->attrs, entry) {
switch(attr->attr->id) {
case Message_Type:
+ case Random_Vector:
break;
case Assigned_Session_ID:
assigned_sid = attr;
@@ -3113,7 +3165,8 @@ static int l2tp_conn_read(struct triton_md_handler_t *h)
int res;
while (1) {
- res = l2tp_recv(h->fd, &pack, NULL);
+ res = l2tp_recv(h->fd, &pack, NULL,
+ conf_secret, conf_secret_len);
if (res) {
if (res == -2) {
log_tunnel(log_info1, conn,
@@ -3320,7 +3373,8 @@ static int l2tp_udp_read(struct triton_md_handler_t *h)
char src_addr[17];
while (1) {
- if (l2tp_recv(h->fd, &pack, &pkt_info))
+ if (l2tp_recv(h->fd, &pack, &pkt_info,
+ conf_secret, conf_secret_len) < 0)
break;
if (!pack)
@@ -3528,6 +3582,7 @@ static int l2tp_create_tunnel_exec(const char *cmd, char * const *fields,
int peer_indx = -1;
int host_indx = -1;
int lns_mode = 0;
+ int hide_avps = conf_hide_avps;
uint16_t tid;
int indx;
@@ -3570,6 +3625,9 @@ static int l2tp_create_tunnel_exec(const char *cmd, char * const *fields,
fields[indx]);
return CLI_CMD_INVAL;
}
+ } else if (strcmp("hide-avps", fields[indx]) == 0) {
+ ++indx;
+ hide_avps = atoi(fields[indx]) > 0;
} else {
cli_sendv(client, "invalid option: \"%s\"\r\n",
fields[indx]);
@@ -3593,7 +3651,7 @@ static int l2tp_create_tunnel_exec(const char *cmd, char * const *fields,
return CLI_CMD_INVAL;
}
- conn = l2tp_tunnel_alloc(&peer, &host, 3, lns_mode, 0);
+ conn = l2tp_tunnel_alloc(&peer, &host, 3, lns_mode, 0, hide_avps);
if (conn == NULL) {
cli_send(client, "tunnel allocation failed\r\n");
return CLI_CMD_FAILED;
@@ -3663,7 +3721,7 @@ static void l2tp_create_tunnel_help(char * const *fields, int fields_cnt,
{
cli_send(client,
"l2tp create tunnel peer-addr <ip_addr> [host-addr <ip_addr>]"
- " [mode <lac|lns>]"
+ " [hide-avps <0|1>] [mode <lac|lns>]"
" - initiate new tunnel to peer\r\n");
}
@@ -3689,6 +3747,10 @@ static void load_config(void)
if (opt && atoi(opt) >= 0)
conf_verbose = atoi(opt) > 0;
+ opt = conf_get_opt("l2tp", "hide-avps");
+ if (opt && atoi(opt) >= 0)
+ conf_hide_avps = atoi(opt) > 0;
+
opt = conf_get_opt("l2tp", "avp_permissive");
if (opt && atoi(opt) >= 0)
conf_avp_permissive = atoi(opt) > 0;
@@ -3716,8 +3778,10 @@ static void load_config(void)
conf_host_name = "accel-ppp";
opt = conf_get_opt("l2tp", "secret");
- if (opt)
+ if (opt) {
conf_secret = opt;
+ conf_secret_len = strlen(opt);
+ }
opt = conf_get_opt("l2tp", "dir300_quirk");
if (opt)
diff --git a/accel-pppd/ctrl/l2tp/l2tp.h b/accel-pppd/ctrl/l2tp/l2tp.h
index 3c26c9f..b816bc8 100644
--- a/accel-pppd/ctrl/l2tp/l2tp.h
+++ b/accel-pppd/ctrl/l2tp/l2tp.h
@@ -63,6 +63,10 @@ struct l2tp_packet_t
struct sockaddr_in addr;
struct l2tp_hdr_t hdr;
struct list_head attrs;
+ struct l2tp_attr_t *last_RV;
+ const char *secret;
+ size_t secret_len;
+ int hide_avps;
};
extern int conf_verbose;
@@ -73,15 +77,18 @@ struct l2tp_dict_attr_t *l2tp_dict_find_attr_by_id(int id);
const struct l2tp_dict_value_t *l2tp_dict_find_value(const struct l2tp_dict_attr_t *attr,
l2tp_value_t val);
-int l2tp_recv(int fd, struct l2tp_packet_t **, struct in_pktinfo *);
+int l2tp_recv(int fd, struct l2tp_packet_t **, struct in_pktinfo *,
+ const char *secret, size_t secret_len);
void l2tp_packet_free(struct l2tp_packet_t *);
void l2tp_packet_print(const struct l2tp_packet_t *,
void (*print)(const char *fmt, ...));
struct l2tp_packet_t *l2tp_packet_alloc(int ver, int msg_type,
- const struct sockaddr_in *addr);
+ const struct sockaddr_in *addr, int H,
+ const char *secret, size_t secret_len);
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 M);
int l2tp_packet_add_int32(struct l2tp_packet_t *pack, int id, int32_t val, int M);
+int l2tp_packet_add_int64(struct l2tp_packet_t *pack, int id, int64_t val, int M);
int l2tp_packet_add_string(struct l2tp_packet_t *pack, int id, const char *val, int M);
int l2tp_packet_add_octets(struct l2tp_packet_t *pack, int id, const uint8_t *val, int size, int M);
diff --git a/accel-pppd/ctrl/l2tp/packet.c b/accel-pppd/ctrl/l2tp/packet.c
index 87735a2..e4278a3 100644
--- a/accel-pppd/ctrl/l2tp/packet.c
+++ b/accel-pppd/ctrl/l2tp/packet.c
@@ -1,16 +1,19 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <endian.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>
+#include "crypto.h"
#include "triton.h"
#include "log.h"
#include "mempool.h"
#include "memdebug.h"
+#include "utils.h"
#include "l2tp.h"
#include "attr_defs.h"
@@ -38,6 +41,8 @@ void l2tp_packet_print(const struct l2tp_packet_t *pack,
val = l2tp_dict_find_value(attr->attr, attr->val);
if (val)
print(" %s", val->name);
+ else if (attr->H)
+ print(" (hidden, %hu bytes)", attr->length);
else {
switch (attr->attr->type) {
case ATTR_TYPE_INT16:
@@ -58,7 +63,8 @@ void l2tp_packet_print(const struct l2tp_packet_t *pack,
}
struct l2tp_packet_t *l2tp_packet_alloc(int ver, int msg_type,
- const struct sockaddr_in *addr)
+ const struct sockaddr_in *addr, int H,
+ const char *secret, size_t secret_len)
{
struct l2tp_packet_t *pack = mempool_alloc(pack_pool);
if (!pack)
@@ -71,6 +77,9 @@ struct l2tp_packet_t *l2tp_packet_alloc(int ver, int msg_type,
pack->hdr.L = 1;
pack->hdr.S = 1;
memcpy(&pack->addr, addr, sizeof(*addr));
+ pack->hide_avps = H;
+ pack->secret = secret;
+ pack->secret_len = secret_len;
if (msg_type) {
if (l2tp_packet_add_int16(pack, Message_Type, msg_type, 1)) {
@@ -88,7 +97,8 @@ void l2tp_packet_free(struct l2tp_packet_t *pack)
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)
+ if (attr->H || attr->attr->type == ATTR_TYPE_OCTETS
+ || attr->attr->type == ATTR_TYPE_STRING)
_free(attr->val.octets);
list_del(&attr->entry);
mempool_free(attr);
@@ -97,7 +107,126 @@ void l2tp_packet_free(struct l2tp_packet_t *pack)
mempool_free(pack);
}
-int l2tp_recv(int fd, struct l2tp_packet_t **p, struct in_pktinfo *pkt_info)
+static void memxor(uint8_t *dst, const uint8_t *src, size_t sz)
+{
+ const uintmax_t *umax_src = (const uintmax_t *)src;
+ uintmax_t *umax_dst = (uintmax_t *)dst;
+ size_t left = sz % sizeof(uintmax_t);
+ size_t indx;
+
+ for (indx = 0; indx < sz / sizeof(uintmax_t); ++indx)
+ umax_dst[indx] ^= umax_src[indx];
+
+ src += sz - left;
+ dst += sz - left;
+ while (left) {
+ if (left >= sizeof(uint32_t)) {
+ *(uint32_t *)dst ^= *(uint32_t *)src;
+ src += sizeof(uint32_t);
+ dst += sizeof(uint32_t);
+ left -= sizeof(uint32_t);
+ } else if (left >= sizeof(uint16_t)) {
+ *(uint16_t *)dst ^= *(uint16_t *)src;
+ src += sizeof(uint16_t);
+ dst += sizeof(uint16_t);
+ left -= sizeof(uint16_t);
+ } else {
+ *dst ^= *src;
+ src += sizeof(uint8_t);
+ dst += sizeof(uint8_t);
+ left -= sizeof(uint8_t);
+ }
+ }
+}
+
+/*
+ * Decipher hidden AVPs, keeping the Hidden AVP Subformat (i.e. the attribute
+ * value is prefixed by 2 bytes indicating its length in network byte order).
+ */
+static int decode_avp(struct l2tp_avp_t *avp, const struct l2tp_attr_t *RV,
+ const char *secret, size_t secret_len)
+{
+ MD5_CTX md5_ctx;
+ uint8_t md5[MD5_DIGEST_LENGTH];
+ uint8_t p1[MD5_DIGEST_LENGTH];
+ uint8_t *prev_block = NULL;
+ uint16_t attr_len;
+ uint16_t orig_attr_len;
+ uint16_t bytes_left;
+ uint16_t blocks_left;
+ uint16_t last_block_len;
+
+ if (avp->length < sizeof(struct l2tp_avp_t) + 2) {
+ /* Hidden AVPs must contain at least two bytes
+ for storing original attribute length */
+ log_warn("l2tp: incorrect hidden avp received (type %hu):"
+ " length too small (%hu bytes)\n",
+ ntohs(avp->type), avp->length);
+ return -1;
+ }
+ attr_len = avp->length - sizeof(struct l2tp_avp_t);
+
+ /* Decode first block */
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, &avp->type, sizeof(avp->type));
+ MD5_Update(&md5_ctx, secret, secret_len);
+ MD5_Update(&md5_ctx, RV->val.octets, RV->length);
+ MD5_Final(p1, &md5_ctx);
+
+ if (attr_len <= MD5_DIGEST_LENGTH) {
+ memxor(avp->val, p1, attr_len);
+ return 0;
+ }
+
+ memxor(p1, avp->val, MD5_DIGEST_LENGTH);
+ orig_attr_len = ntohs(*(uint16_t *)p1);
+
+ if (orig_attr_len <= MD5_DIGEST_LENGTH - 2) {
+ /* Enough bytes decoded already, no need to decode padding */
+ memcpy(avp->val, p1, MD5_DIGEST_LENGTH);
+ return 0;
+ }
+
+ if (orig_attr_len > attr_len - 2) {
+ log_warn("l2tp: incorrect hidden avp received (type %hu):"
+ " original attribute length too big (ciphered"
+ " attribute length: %hu bytes, advertised original"
+ " attribute length: %hu bytes)\n",
+ ntohs(avp->type), attr_len, orig_attr_len);
+ return -1;
+ }
+
+ /* Decode remaining blocks. Start from the last block as
+ preceding blocks must be kept hidden for computing MD5s */
+ bytes_left = orig_attr_len + 2 - MD5_DIGEST_LENGTH;
+ last_block_len = bytes_left % MD5_DIGEST_LENGTH;
+ blocks_left = bytes_left / MD5_DIGEST_LENGTH;
+ if (last_block_len) {
+ prev_block = avp->val + blocks_left * MD5_DIGEST_LENGTH;
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, secret, secret_len);
+ MD5_Update(&md5_ctx, prev_block, MD5_DIGEST_LENGTH);
+ MD5_Final(md5, &md5_ctx);
+ memxor(prev_block + MD5_DIGEST_LENGTH, md5, last_block_len);
+ prev_block -= MD5_DIGEST_LENGTH;
+ } else
+ prev_block = avp->val + (blocks_left - 1) * MD5_DIGEST_LENGTH;
+
+ while (prev_block >= avp->val) {
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, secret, secret_len);
+ MD5_Update(&md5_ctx, prev_block, MD5_DIGEST_LENGTH);
+ MD5_Final(md5, &md5_ctx);
+ memxor(prev_block + MD5_DIGEST_LENGTH, md5, MD5_DIGEST_LENGTH);
+ prev_block -= MD5_DIGEST_LENGTH;
+ }
+ memcpy(avp->val, p1, MD5_DIGEST_LENGTH);
+
+ return 0;
+}
+
+int l2tp_recv(int fd, struct l2tp_packet_t **p, struct in_pktinfo *pkt_info,
+ const char *secret, size_t secret_len)
{
int n, length;
uint8_t *buf;
@@ -112,6 +241,8 @@ int l2tp_recv(int fd, struct l2tp_packet_t **p, struct in_pktinfo *pkt_info)
struct msghdr msg;
char msg_control[128];
struct cmsghdr *cmsg;
+ uint16_t orig_avp_len;
+ void *orig_avp_val;
*p = NULL;
@@ -252,51 +383,65 @@ int l2tp_recv(int fd, struct l2tp_packet_t **p, struct in_pktinfo *pkt_info)
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));
}
+ if (secret == NULL || secret_len == 0) {
+ log_error("l2tp: impossible to decode"
+ " hidden avp (type %hu): no"
+ " secret set)\n",
+ ntohs(avp->type));
+ goto out_err;
+ }
+ if (decode_avp(avp, RV, secret, secret_len) < 0)
+ goto out_err;
}
attr = mempool_alloc(attr_pool);
memset(attr, 0, sizeof(*attr));
list_add_tail(&attr->entry, &pack->attrs);
+ if (avp->H) {
+ orig_avp_len = ntohs(*(uint16_t *)avp->val) + sizeof(*avp);
+ orig_avp_val = avp->val + sizeof(uint16_t);
+ } else {
+ orig_avp_len = avp->length;
+ orig_avp_val = avp->val;
+ }
+
attr->attr = da;
attr->M = avp->M;
- attr->H = avp->H;
- attr->length = avp->length - sizeof(*avp);
-
+ attr->H = 0;
+ attr->length = orig_avp_len - sizeof(*avp);
+
if (attr->attr->id == Random_Vector)
RV = attr;
switch (da->type) {
case ATTR_TYPE_INT16:
- if (avp->length != sizeof(*avp) + 2)
+ if (orig_avp_len != sizeof(*avp) + 2)
goto out_err_len;
- attr->val.uint16 = ntohs(*(uint16_t *)avp->val);
+ attr->val.uint16 = ntohs(*(uint16_t *)orig_avp_val);
break;
case ATTR_TYPE_INT32:
- if (avp->length != sizeof(*avp) + 4)
+ if (orig_avp_len != sizeof(*avp) + 4)
goto out_err_len;
- attr->val.uint32 = ntohl(*(uint32_t *)avp->val);
+ attr->val.uint32 = ntohl(*(uint32_t *)orig_avp_val);
break;
case ATTR_TYPE_INT64:
- if (avp->length != sizeof(*avp) + 8)
+ if (orig_avp_len != sizeof(*avp) + 8)
goto out_err_len;
- attr->val.uint64 = *(uint64_t *)avp->val;
+ attr->val.uint64 = be64toh(*(uint64_t *)orig_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);
+ memcpy(attr->val.octets, orig_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);
+ memcpy(attr->val.string, orig_avp_val, attr->length);
attr->val.string[attr->length] = 0;
break;
}
@@ -319,7 +464,7 @@ out_err_hdr:
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);
+ log_warn("l2tp: incorrect avp received (type=%i, incorrect length %i)\n", ntohs(avp->type), orig_avp_len);
goto out_err;
out_err_mem:
log_emerg("l2tp: out of memory\n");
@@ -356,19 +501,24 @@ int l2tp_packet_send(int sock, struct l2tp_packet_t *pack)
avp->H = attr->H;
avp->length = sizeof(*avp) + attr->length;
*(uint16_t *)ptr = htons(*(uint16_t *)ptr);
- switch (attr->attr->type) {
+ if (attr->H)
+ memcpy(avp->val, attr->val.octets, attr->length);
+ else
+ 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_INT64:
+ *(uint64_t *)avp->val = htobe64(attr->val.uint64);
+ 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;
}
@@ -399,7 +549,120 @@ int l2tp_packet_send(int sock, struct l2tp_packet_t *pack)
return 0;
}
-static struct l2tp_attr_t *attr_alloc(int id, int M)
+int encode_attr(const struct l2tp_packet_t *pack, struct l2tp_attr_t *attr,
+ const void *val, uint16_t val_len)
+{
+ uint8_t *u8_ptr = NULL;
+ uint8_t md5[MD5_DIGEST_LENGTH];
+ MD5_CTX md5_ctx;
+ uint16_t pad_len;
+ uint16_t attr_type;
+ uint16_t blocks_left;
+ uint16_t last_block_len;
+ int err;
+
+ if (pack->secret == NULL || pack->secret_len == 0) {
+ log_error("l2tp: impossible to hide AVP: no secret\n");
+ goto err;
+ }
+ if (pack->last_RV == NULL) {
+ log_error("l2tp: impossible to hide AVP: no random vector\n");
+ goto err;
+ }
+
+ if (u_randbuf(&pad_len, sizeof(pad_len), &err) < 0) {
+ if (err)
+ log_error("l2tp: impossible to hide AVP:"
+ " reading from urandom failed: %s\n",
+ strerror(err));
+ else
+ log_error("l2tp: impossible to hide AVP:"
+ " end of file reached while reading"
+ " from urandom\n");
+ goto err;
+ }
+ /* Use at least 16 bytes of padding */
+ pad_len = (pad_len & 0x007F) + 16;
+
+ /* Generate Hidden AVP Subformat:
+ * -original AVP size (2 bytes, network byte order)
+ * -original AVP value ('val_len' bytes)
+ * -padding ('pad_len' bytes of random values)
+ */
+ attr->length = sizeof(val_len) + val_len + pad_len;
+ attr->val.octets = _malloc(attr->length);
+ if (attr->val.octets == NULL) {
+ log_error("l2tp: impossible to hide AVP:"
+ " memory allocation failed\n");
+ goto err;
+ }
+
+ *(uint16_t *)attr->val.octets = htons(val_len);
+ memcpy(attr->val.octets + sizeof(val_len), val, val_len);
+
+ if (u_randbuf(attr->val.octets + sizeof(val_len) + val_len,
+ pad_len, &err) < 0) {
+ if (err)
+ log_error("l2tp: impossible to hide AVP:"
+ " reading from urandom failed: %s\n",
+ strerror(err));
+ else
+ log_error("l2tp: impossible to hide AVP:"
+ " end of file reached while reading"
+ " from urandom\n");
+ goto err_free;
+ }
+
+ /* Hidden AVP cipher:
+ * ciphered[0] = clear[0] xor MD5(attr_type, secret, RV)
+ * ciphered[1] = clear[1] xor MD5(secret, ciphered[0])
+ * ...
+ * ciphered[n] = clear[n] xor MD5(secret, ciphered[n-1])
+ */
+ attr_type = htons(attr->attr->id);
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, &attr_type, sizeof(attr_type));
+ MD5_Update(&md5_ctx, pack->secret, pack->secret_len);
+ MD5_Update(&md5_ctx, pack->last_RV->val.octets, pack->last_RV->length);
+ MD5_Final(md5, &md5_ctx);
+
+ if (attr->length <= MD5_DIGEST_LENGTH) {
+ memxor(attr->val.octets, md5, attr->length);
+ return 0;
+ }
+
+ memxor(attr->val.octets, md5, MD5_DIGEST_LENGTH);
+
+ blocks_left = attr->length / MD5_DIGEST_LENGTH - 1;
+ last_block_len = attr->length % MD5_DIGEST_LENGTH;
+
+ for (u8_ptr = attr->val.octets; blocks_left; --blocks_left) {
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, pack->secret, pack->secret_len);
+ MD5_Update(&md5_ctx, u8_ptr, MD5_DIGEST_LENGTH);
+ MD5_Final(md5, &md5_ctx);
+ u8_ptr += MD5_DIGEST_LENGTH;
+ memxor(u8_ptr, md5, MD5_DIGEST_LENGTH);
+ }
+
+ if (last_block_len) {
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, pack->secret, pack->secret_len);
+ MD5_Update(&md5_ctx, u8_ptr, MD5_DIGEST_LENGTH);
+ MD5_Final(md5, &md5_ctx);
+ memxor(u8_ptr + MD5_DIGEST_LENGTH, md5, last_block_len);
+ }
+
+ return 0;
+
+err_free:
+ _free(attr->val.octets);
+ attr->val.octets = NULL;
+err:
+ return -1;
+}
+
+static struct l2tp_attr_t *attr_alloc(int id, int M, int H)
{
struct l2tp_attr_t *attr;
struct l2tp_dict_attr_t *da;
@@ -423,76 +686,210 @@ static struct l2tp_attr_t *attr_alloc(int id, int M)
else
attr->M = M;
- //if (da->H != -1)
- //attr->H = da->H;
+ if (da->H != -1)
+ attr->H = da->H;
+ else
+ attr->H = H;
return attr;
}
+static int l2tp_packet_add_random_vector(struct l2tp_packet_t *pack)
+{
+ struct l2tp_attr_t *attr = attr_alloc(Random_Vector, 1, 0);
+ uint16_t ranvec_len;
+ int err;
+
+ if (!attr)
+ goto err;
+
+ if (u_randbuf(&ranvec_len, sizeof(ranvec_len), &err) < 0) {
+ if (err)
+ log_error("l2tp: impossible to build Random Vector:"
+ " reading from urandom failed: %s\n",
+ strerror(err));
+ else
+ log_error("l2tp: impossible to build Random Vector:"
+ " end of file reached while reading"
+ " from urandom\n");
+ goto err_attr;
+ }
+ /* RFC 2661 recommends that Random Vector be least 16 bytes long */
+ ranvec_len = (ranvec_len & 0x007F) + 16;
+
+ attr->length = ranvec_len;
+ attr->val.octets = _malloc(ranvec_len);
+ if (!attr->val.octets) {
+ log_emerg("l2tp: out of memory\n");
+ goto err_attr;
+ }
+
+ if (u_randbuf(attr->val.octets, ranvec_len, &err) < 0) {
+ if (err)
+ log_error("l2tp: impossible to build Random Vector:"
+ " reading from urandom failed: %s\n",
+ strerror(err));
+ else
+ log_error("l2tp: impossible to build Random Vector:"
+ " end of file reached while reading"
+ " from urandom\n");
+ goto err_attr_val;
+ }
+
+ list_add_tail(&attr->entry, &pack->attrs);
+ pack->last_RV = attr;
+
+ return 0;
+
+err_attr_val:
+ _free(attr->val.octets);
+err_attr:
+ mempool_free(attr);
+err:
+ return -1;
+}
+
int l2tp_packet_add_int16(struct l2tp_packet_t *pack, int id, int16_t val, int M)
{
- struct l2tp_attr_t *attr = attr_alloc(id, M);
+ struct l2tp_attr_t *attr = attr_alloc(id, M, pack->hide_avps);
if (!attr)
return -1;
- attr->length = 2;
- attr->val.int16 = val;
+ if (attr->H) {
+ if (pack->last_RV == NULL)
+ if (l2tp_packet_add_random_vector(pack) < 0)
+ goto err;
+ val = htons(val);
+ if (encode_attr(pack, attr, &val, sizeof(val)) < 0)
+ goto err;
+ } else {
+ attr->length = sizeof(val);
+ attr->val.int16 = val;
+ }
list_add_tail(&attr->entry, &pack->attrs);
return 0;
+
+err:
+ mempool_free(attr);
+ return -1;
}
+
int l2tp_packet_add_int32(struct l2tp_packet_t *pack, int id, int32_t val, int M)
{
- struct l2tp_attr_t *attr = attr_alloc(id, M);
+ struct l2tp_attr_t *attr = attr_alloc(id, M, pack->hide_avps);
+
+ if (!attr)
+ return -1;
+
+ if (attr->H) {
+ if (pack->last_RV == NULL)
+ if (l2tp_packet_add_random_vector(pack) < 0)
+ goto err;
+ val = htonl(val);
+ if (encode_attr(pack, attr, &val, sizeof(val)) < 0)
+ goto err;
+ } else {
+ attr->length = sizeof(val);
+ attr->val.int32 = val;
+ }
+ list_add_tail(&attr->entry, &pack->attrs);
+
+ return 0;
+
+err:
+ mempool_free(attr);
+ return -1;
+}
+
+int l2tp_packet_add_int64(struct l2tp_packet_t *pack, int id, int64_t val, int M)
+{
+ struct l2tp_attr_t *attr = attr_alloc(id, M, pack->hide_avps);
if (!attr)
return -1;
- attr->length = 4;
- attr->val.int32 = val;
+ if (attr->H) {
+ if (pack->last_RV == NULL)
+ if (l2tp_packet_add_random_vector(pack) < 0)
+ goto err;
+ val = htobe64(val);
+ if (encode_attr(pack, attr, &val, sizeof(val)) < 0)
+ goto err;
+ } else {
+ attr->length = sizeof(val);
+ attr->val.uint64 = val;
+ }
list_add_tail(&attr->entry, &pack->attrs);
return 0;
+
+err:
+ mempool_free(attr);
+ return -1;
}
+
int l2tp_packet_add_string(struct l2tp_packet_t *pack, int id, const char *val, int M)
{
- struct l2tp_attr_t *attr = attr_alloc(id, M);
+ struct l2tp_attr_t *attr = attr_alloc(id, M, pack->hide_avps);
+ size_t val_len = strlen(val);
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;
+ if (attr->H) {
+ if (pack->last_RV == NULL)
+ if (l2tp_packet_add_random_vector(pack) < 0)
+ goto err;
+ if (encode_attr(pack, attr, val, val_len) < 0)
+ goto err;
+ } else {
+ attr->length = val_len;
+ attr->val.string = _strdup(val);
+ if (!attr->val.string) {
+ log_emerg("l2tp: out of memory\n");
+ goto err;
+ }
}
- memcpy(attr->val.string, val, attr->length);
list_add_tail(&attr->entry, &pack->attrs);
return 0;
+
+err:
+ mempool_free(attr);
+ return -1;
}
int l2tp_packet_add_octets(struct l2tp_packet_t *pack, int id, const uint8_t *val, int size, int M)
{
- struct l2tp_attr_t *attr = attr_alloc(id, M);
+ struct l2tp_attr_t *attr = attr_alloc(id, M, pack->hide_avps);
if (!attr)
return -1;
- attr->length = size;
- attr->val.octets = _malloc(size);
- if (!attr->val.octets) {
- log_emerg("l2tp: out of memory\n");
- mempool_free(attr);
- return -1;
+ if (attr->H) {
+ if (pack->last_RV == NULL)
+ if (l2tp_packet_add_random_vector(pack) < 0)
+ goto err;
+ if (encode_attr(pack, attr, val, size) < 0)
+ goto err;
+ } else {
+ attr->length = size;
+ attr->val.octets = _malloc(size);
+ if (!attr->val.octets) {
+ log_emerg("l2tp: out of memory\n");
+ goto err;
+ }
+ memcpy(attr->val.octets, val, attr->length);
}
- memcpy(attr->val.octets, val, attr->length);
list_add_tail(&attr->entry, &pack->attrs);
return 0;
+
+err:
+ mempool_free(attr);
+ return -1;
}
static void init(void)