Skip to content

Commit

Permalink
SCTP: Support ASCONF/-ACK chunk
Browse files Browse the repository at this point in the history
Add support for printing ASCONF and ASCONF-ACK chunk based on RFC5061.

Remove REL_CNTL(0xc1) because it's obsolete and conflicts with ASCONF.

Prints all ASCONF parameters with `-vv` set.

Example:
`-v`: [ASCONF] [SEQ: .., ADDR: 192...] [DEL ADDR]
`-vv`:[ASCONF] [SEQ: .., ADDR: 192...] [DEL ADDR: C-ID: 0, ADDR: 192...]
[ASCONF-ACK] [SEQ: 4161214189]
  • Loading branch information
Yuxuan Luo authored and fxlb committed Apr 30, 2023
1 parent 66897e9 commit d619e61
Showing 1 changed file with 217 additions and 2 deletions.
219 changes: 217 additions & 2 deletions print-sctp.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,10 @@
#define SCTP_ECN_CWR 0x0d
#define SCTP_SHUTDOWN_COMPLETE 0x0e
#define SCTP_I_DATA 0x40
#define SCTP_ASCONF_ACK 0x80
#define SCTP_RE_CONFIG 0x82
#define SCTP_FORWARD_CUM_TSN 0xc0
#define SCTP_RELIABLE_CNTL 0xc1
#define SCTP_ASCONF 0xc1
#define SCTP_I_FORWARD_TSN 0xc2

static const struct tok sctp_chunkid_str[] = {
Expand All @@ -136,7 +137,8 @@ static const struct tok sctp_chunkid_str[] = {
{ SCTP_I_DATA, "I-DATA" },
{ SCTP_RE_CONFIG, "RE-CONFIG" },
{ SCTP_FORWARD_CUM_TSN, "FOR CUM TSN" },
{ SCTP_RELIABLE_CNTL, "REL CTRL" },
{ SCTP_ASCONF, "ASCONF" },
{ SCTP_ASCONF_ACK, "ASCONF-ACK" },
{ SCTP_I_FORWARD_TSN, "I-FORWARD-FSN" },
{ 0, NULL }
};
Expand All @@ -163,6 +165,18 @@ static const struct tok sctp_chunkid_str[] = {

#define SCTP_ADDRMAX 60

/* ASCONF Parameters*/
/* - used in INIT/ACK chunk */
#define SET_PRI_ADDR 0xC004
#define ADAPT_LAYER_INDIC 0xC006
#define SUPPORTED_EXT 0x8008
/* - used in ASCONF param */
#define ADD_IP_ADDR 0xC001
#define DEL_IP_ADDR 0xC002
/* - used in ASCONF response */
#define ERR_CAUSE_INDIC 0xC003
#define SUCCESS_INDIC 0xC005

#define CHAN_HP 6704
#define CHAN_MP 6705
#define CHAN_LP 6706
Expand Down Expand Up @@ -411,6 +425,35 @@ struct addStreamReq{
nd_uint16_t reserved;
};

/* ASCONF parameters */
struct sctpAsconfParam{
nd_uint16_t type;
nd_uint16_t length;
nd_uint32_t CID;
union {
struct sctpV4IpAddress ipv4;
struct sctpV6IpAddress ipv6;
} addr;
};

struct sctpASCONF{
nd_uint32_t seq_num;
union {
struct sctpV4IpAddress ipv4;
struct sctpV6IpAddress ipv6;
} addr;
};

struct sctpASCONF_ACK{
nd_uint32_t seq_num;
};

struct sctpErrParam{
nd_uint8_t type;
nd_uint8_t flags;
nd_uint16_t length;
};

struct sctpUnifiedDatagram{
struct sctpChunkDesc uh;
struct sctpDataPart dp;
Expand Down Expand Up @@ -448,6 +491,34 @@ static const struct tok results[] = {
{ 6, "In progress" },
};

/* ASCONF tokens */
static const struct tok asconfigParams[] = {
{ SET_PRI_ADDR, "SET PRIM ADDR" },
{ ADAPT_LAYER_INDIC, "Adaptation Layer Indication" },
{ SUPPORTED_EXT, "Supported Extensions" },
{ ADD_IP_ADDR, "ADD ADDR" },
{ DEL_IP_ADDR, "DEL ADDR" },
{ ERR_CAUSE_INDIC, "ERR" },
{ SUCCESS_INDIC, "SUCCESS" },
};

static const struct tok causeCode[] = {
{ 1, "Invalid Stream Identifier" },
{ 2, "Missing Mandatory Parameter" },
{ 3, "Stale Cookie Error" },
{ 4, "Out of Resource" },
{ 5, "Unresolvable Address" },
{ 6, "Unrecognized Chunk Type" },
{ 7, "Invalid Mandatory Parameter" },
{ 8, "Unrecognized Parameters" },
{ 9, "No User Data" },
{ 10, "Cookie Received While Shutting Down" },
{ 11, "Restart of an Association with New Addresses" },
{ 12, "User Initiated Abort" },
{ 13, "Protocol Violation" },
{ 0, NULL }
};

static const struct tok ForCES_channels[] = {
{ CHAN_HP, "ForCES HP" },
{ CHAN_MP, "ForCES MP" },
Expand Down Expand Up @@ -1114,6 +1185,150 @@ sctp_print(netdissect_options *ndo,
bp += padding_len;
}

break;
}
case SCTP_ASCONF:
{
const struct sctpASCONF *content;
const struct sctpAsconfParam *param;
size_t length;
uint16_t param_len;

ND_ICHECKMSG_ZU("chunk length", chunkLengthRemaining, <, sizeof(*content));
content = (const struct sctpASCONF*) bp;
ND_PRINT("[SEQ: %u, ", GET_BE_U_4(content->seq_num));

if (GET_BE_U_2(content->addr.ipv4.p.paramType) == 5) { /* IPv4 */
length = sizeof(nd_uint32_t) + sizeof(struct sctpV4IpAddress);
ND_ICHECKMSG_ZU("chunk length", chunkLengthRemaining, <, length);
ND_PRINT("ADDR: %s] ", GET_IPADDR_STRING(content->addr.ipv4.ipAddress));
} else if (GET_BE_U_2(content->addr.ipv6.p.paramType) == 6) { /* IPv6 */
length = sizeof(nd_uint32_t) + sizeof(struct sctpV6IpAddress);
ND_ICHECKMSG_ZU("chunk length", chunkLengthRemaining, <, length);
ND_PRINT("ADDR: %s] ", GET_IP6ADDR_STRING(content->addr.ipv4.ipAddress));
} else {
length = sizeof(nd_uint32_t) + GET_BE_U_2(content->addr.ipv4.p.paramLength);
ND_ICHECKMSG_ZU("chunk length", chunkLengthRemaining, <, length);
ND_PRINT("ADDR: bogus address type]");
}
bp += length;
chunkLengthRemaining -= length;
sctpPacketLengthRemaining -= length;

while (0 != chunkLengthRemaining) {
ND_ICHECKMSG_ZU("chunk length", chunkLengthRemaining, <, sizeof(uint32_t)); /* ensure param_len can be extracted */
param = (const struct sctpAsconfParam*) bp;
param_len = GET_BE_U_2(param->length);

ND_ICHECKMSG_U("chunk length", chunkLengthRemaining, <, param_len);
bp += param_len;
chunkLengthRemaining -= param_len;
sctpPacketLengthRemaining -= param_len;

ND_PRINT("[%s", tok2str(asconfigParams, NULL, GET_BE_U_2(param->type)));

if (ndo->ndo_vflag >= 2) {
ND_PRINT(": C-ID: %u, ", GET_BE_U_4(param->CID));
if (GET_BE_U_2(param->addr.ipv4.p.paramType) == 5) { /* IPv4 */
length = sizeof(nd_uint32_t) + sizeof(struct sctpV4IpAddress);
ND_ICHECKMSG_ZU("param length", param_len, <, length);
ND_PRINT("ADDR: %s] ", GET_IPADDR_STRING(param->addr.ipv4.ipAddress));
} else if (GET_BE_U_2(param->addr.ipv4.p.paramType) == 6) { /* IPv6 */
length = sizeof(nd_uint32_t) + sizeof(struct sctpV6IpAddress);
ND_ICHECKMSG_ZU("param length", param_len, <, length);
ND_PRINT("ADDR: %s] ", GET_IP6ADDR_STRING(param->addr.ipv6.ipAddress));
} else {
ND_PRINT("ADDR: bogus address type]");
}
} else {
ND_PRINT("]");
}
}
break;
}
case SCTP_ASCONF_ACK:
{
const struct sctpASCONF_ACK *content;
const struct sctpAsconfParam *header;
uint16_t param_len;

ND_ICHECKMSG_ZU("chunk length", chunkLengthRemaining, <, sizeof(*content));
content = (const struct sctpASCONF_ACK*) bp;
ND_PRINT("[SEQ: %u] ", GET_BE_U_4(content->seq_num));

bp += sizeof(*content);
chunkLengthRemaining -= sizeof(*content);
sctpPacketLengthRemaining -= sizeof(*content);

while (0 != chunkLengthRemaining) {
ND_ICHECKMSG_ZU("chunk length", chunkLengthRemaining, <, sizeof(*header));
header = (const struct sctpAsconfParam*) bp;
param_len = GET_BE_U_2(header->length);
ND_ICHECKMSG_U("chunk length", chunkLengthRemaining, <, param_len);

ND_PRINT("[%s", tok2str(asconfigParams, NULL, GET_BE_U_2(header->type)));

/* print payload only when vflag >= 2 */
if (ndo->ndo_vflag < 2) {
ND_PRINT("] ");
bp += param_len;
chunkLengthRemaining -= param_len;
sctpPacketLengthRemaining -= param_len;
continue;
}

bp += sizeof(*header);
chunkLengthRemaining -= sizeof(*header);
sctpPacketLengthRemaining -= sizeof(*header);

switch (GET_BE_U_2(header->type)) {
case ERR_CAUSE_INDIC:
{
const struct sctpErrParam *errHdr;
const struct sctpOpErrorCause *err_cause;
uint16_t param_remaining;
uint16_t cause_len;

ND_ICHECKMSG_ZU("chunk length", chunkLengthRemaining, <, sizeof(struct sctpErrParam));
errHdr = (const struct sctpErrParam*) bp;
param_remaining = GET_BE_U_2(errHdr->length);
ND_ICHECKMSG_U("chunk length", chunkLengthRemaining, <, param_remaining);

bp += sizeof(*errHdr);
chunkLengthRemaining -= sizeof(*errHdr);
sctpPacketLengthRemaining -= sizeof(*errHdr);

ND_PRINT(": ");
while (0 != param_remaining) {
ND_ICHECKMSG_ZU("chunk length", chunkLengthRemaining, <, sizeof(*err_cause));
err_cause = (const struct sctpOpErrorCause*) bp;
ND_PRINT(" %s, ", tok2str(causeCode, NULL, GET_BE_U_2(err_cause->cause)));

cause_len = GET_BE_U_2(err_cause->causeLen);
ND_ICHECKMSG_ZU("cause length", cause_len, <, sizeof(*err_cause));
ND_ICHECKMSG_U("param length", param_remaining, <, cause_len);
bp += cause_len;
param_remaining -= cause_len;
chunkLengthRemaining -= cause_len;
sctpPacketLengthRemaining -= cause_len;
}
ND_PRINT("] ");
break;
}
case SUCCESS_INDIC:
{
ND_PRINT(": C-ID %u] ", GET_BE_U_4(bp));
bp += sizeof(uint32_t);
break;
}
default:
{
ND_PRINT("Unknown parameter] ");
bp += (param_len - sizeof(*header));
break;
}
}
}
break;
}
default :
Expand Down

0 comments on commit d619e61

Please sign in to comment.