From 9ec0d6beda4249ca0483e461bd5fb361f7a28efa Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Tue, 9 Apr 2013 21:43:12 +0200 Subject: l2tp: Full hidden AVPs support Add option "hide-avps" in the "l2tp" section for hiding attributes sent to peer. This same option is also made available on accel-ppp's command line interface: accel-ppp# tunnel create tunnel peer-addr 192.0.2.1 hide-avps 1 Attribute hiding is performed upon attribute creation (in the l2tp_packet_add_*() functions family) rather than upon packet sending. This avoid running the cipher for every retransmission; the counterpart is that l2tp_packet_print() can't dump original attributes of hidden AVPs. Currently, only one random vector is used for all hidden AVPs in a packet. This is easily extensible though, as the 'last_RV' field in struct l2tp_packet_t may be overridden to use new vectors for next AVPs. Signed-off-by: Guillaume Nault --- accel-pppd/accel-ppp.conf.5 | 6 + accel-pppd/ctrl/l2tp/l2tp.c | 64 +++++++--- accel-pppd/ctrl/l2tp/l2tp.h | 7 +- accel-pppd/ctrl/l2tp/packet.c | 289 +++++++++++++++++++++++++++++++++++++----- 4 files changed, 318 insertions(+), 48 deletions(-) (limited to 'accel-pppd') diff --git a/accel-pppd/accel-ppp.conf.5 b/accel-pppd/accel-ppp.conf.5 index 08540215..636fe184 100644 --- a/accel-pppd/accel-ppp.conf.5 +++ b/accel-pppd/accel-ppp.conf.5 @@ -424,6 +424,12 @@ is greater of zero then l2tp module will produce verbose logging. .TP .BI "secret=" string Specifies secret to connect to server. +.TP +.BI "hide-avps=" n +If this option is given and +.B n +is greater than 0, then attributes sent in L2TP packets will be hidden (for +AVPs that support it). .SH [radius] .br Configuration of RADIUS module. diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c index c6ba82ff..d2c6982d 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; @@ -78,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; @@ -101,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; @@ -414,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"); @@ -456,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"); @@ -500,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"); @@ -863,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; @@ -990,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); @@ -1119,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; @@ -1458,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"); @@ -1481,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"); @@ -1501,7 +1511,8 @@ static void l2tp_send_SCCRQ(void *peer_addr) 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"); @@ -1566,7 +1577,8 @@ static void l2tp_send_SCCRP(struct l2tp_conn_t *conn) 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"); @@ -1637,7 +1649,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"); @@ -1673,7 +1686,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"); @@ -1712,7 +1726,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"); @@ -1746,7 +1761,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"); @@ -1790,7 +1806,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"); @@ -1854,7 +1871,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"); @@ -1888,7 +1906,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"); @@ -2008,7 +2027,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); @@ -3533,6 +3553,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; @@ -3575,6 +3596,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]); @@ -3598,7 +3622,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; @@ -3668,7 +3692,7 @@ static void l2tp_create_tunnel_help(char * const *fields, int fields_cnt, { cli_send(client, "l2tp create tunnel peer-addr [host-addr ]" - " [mode ]" + " [hide-avps <0|1>] [mode ]" " - initiate new tunnel to peer\r\n"); } @@ -3694,6 +3718,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; diff --git a/accel-pppd/ctrl/l2tp/l2tp.h b/accel-pppd/ctrl/l2tp/l2tp.h index 82dafd72..566212a3 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; @@ -79,7 +83,8 @@ 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); diff --git a/accel-pppd/ctrl/l2tp/packet.c b/accel-pppd/ctrl/l2tp/packet.c index 5a408405..9bd11eb1 100644 --- a/accel-pppd/ctrl/l2tp/packet.c +++ b/accel-pppd/ctrl/l2tp/packet.c @@ -13,6 +13,7 @@ #include "log.h" #include "mempool.h" #include "memdebug.h" +#include "utils.h" #include "l2tp.h" #include "attr_defs.h" @@ -40,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: @@ -60,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) @@ -73,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)) { @@ -90,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); @@ -493,7 +501,10 @@ 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; @@ -504,8 +515,7 @@ int l2tp_packet_send(int sock, struct l2tp_packet_t *pack) case ATTR_TYPE_OCTETS: memcpy(avp->val, attr->val.string, attr->length); break; - } - + } ptr += sizeof(*avp) + attr->length; len += sizeof(*avp) + attr->length; } @@ -536,7 +546,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; @@ -560,75 +683,183 @@ 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; - 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 = 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_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; + } } 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) -- cgit v1.2.3