diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.in | 1 | ||||
-rw-r--r-- | src/evaluate.c | 16 | ||||
-rw-r--r-- | src/exthdr.c | 26 | ||||
-rw-r--r-- | src/meta.c | 29 | ||||
-rw-r--r-- | src/netlink_delinearize.c | 16 | ||||
-rw-r--r-- | src/parser.y | 36 | ||||
-rw-r--r-- | src/payload.c | 799 | ||||
-rw-r--r-- | src/proto.c | 731 |
8 files changed, 839 insertions, 815 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index 658e9b33..8ac2b460 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -9,6 +9,7 @@ nft-obj += statement.o nft-obj += datatype.o nft-obj += expression.o nft-obj += evaluate.o +nft-obj += proto.o nft-obj += payload.o nft-obj += exthdr.o nft-obj += meta.o diff --git a/src/evaluate.c b/src/evaluate.c index d4f83396..112fc944 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -269,7 +269,7 @@ static int expr_evaluate_primary(struct eval_ctx *ctx, struct expr **expr) static int expr_evaluate_payload(struct eval_ctx *ctx, struct expr **expr) { struct expr *payload = *expr; - enum payload_bases base = payload->payload.base; + enum proto_bases base = payload->payload.base; struct stmt *nstmt; struct expr *nexpr; @@ -916,15 +916,15 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr) left->dtype->desc, right->dtype->desc); /* - * Update payload context for payload and meta iiftype equality - * expressions. + * Update protocol context for payload and meta iiftype + * equality expressions. */ switch (left->ops->type) { case EXPR_PAYLOAD: - payload_ctx_update(&ctx->pctx, rel); + payload_expr_pctx_update(&ctx->pctx, rel); break; case EXPR_META: - payload_ctx_update_meta(&ctx->pctx, rel); + meta_expr_pctx_update(&ctx->pctx, rel); break; case EXPR_CONCAT: return 0; @@ -1117,7 +1117,7 @@ static int stmt_evaluate_reject(struct eval_ctx *ctx, struct stmt *stmt) static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt) { - struct payload_ctx *pctx = &ctx->pctx; + struct proto_ctx *pctx = &ctx->pctx; int err; if (stmt->nat.addr != NULL) { @@ -1133,7 +1133,7 @@ static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt) } if (stmt->nat.proto != NULL) { - if (pctx->protocol[PAYLOAD_BASE_TRANSPORT_HDR].desc == NULL) + if (pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc == NULL) return stmt_binary_error(ctx, stmt->nat.proto, stmt, "transport protocol mapping is only " "valid after transport protocol match"); @@ -1232,7 +1232,7 @@ static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule) struct stmt *stmt, *tstmt = NULL; struct error_record *erec; - payload_ctx_init(&ctx->pctx, rule->handle.family); + proto_ctx_init(&ctx->pctx, rule->handle.family); memset(&ctx->ectx, 0, sizeof(ctx->ectx)); list_for_each_entry(stmt, &rule->stmts, list) { diff --git a/src/exthdr.c b/src/exthdr.c index 3d01c3ab..458f9d62 100644 --- a/src/exthdr.c +++ b/src/exthdr.c @@ -40,14 +40,14 @@ static const struct expr_ops exthdr_expr_ops = { .clone = exthdr_expr_clone, }; -static const struct payload_template exthdr_unknown_template = - PAYLOAD_TEMPLATE("unknown", &invalid_type, 0, 0); +static const struct proto_hdr_template exthdr_unknown_template = + PROTO_HDR_TEMPLATE("unknown", &invalid_type, 0, 0); struct expr *exthdr_expr_alloc(const struct location *loc, const struct exthdr_desc *desc, uint8_t type) { - const struct payload_template *tmpl; + const struct proto_hdr_template *tmpl; struct expr *expr; if (desc != NULL) @@ -73,7 +73,7 @@ static const struct exthdr_desc *exthdr_protocols[IPPROTO_MAX] = { void exthdr_init_raw(struct expr *expr, uint8_t type, unsigned int offset, unsigned int len) { - const struct payload_template *tmpl; + const struct proto_hdr_template *tmpl; unsigned int i; assert(expr->ops->type == EXPR_EXTHDR); @@ -94,9 +94,9 @@ void exthdr_init_raw(struct expr *expr, uint8_t type, } #define HDR_TEMPLATE(__name, __dtype, __type, __member) \ - PAYLOAD_TEMPLATE(__name, __dtype, \ - offsetof(__type, __member) * 8, \ - field_sizeof(__type, __member) * 8) + PROTO_HDR_TEMPLATE(__name, __dtype, \ + offsetof(__type, __member) * 8, \ + field_sizeof(__type, __member) * 8) /* * Hop-by-hop options @@ -171,12 +171,12 @@ const struct exthdr_desc exthdr_frag = { .templates = { [FRAGHDR_NEXTHDR] = FRAG_FIELD("nexthdr", ip6f_nxt, &inet_protocol_type), [FRAGHDR_RESERVED] = FRAG_FIELD("reserved", ip6f_reserved, &integer_type), - [FRAGHDR_FRAG_OFF] = PAYLOAD_TEMPLATE("frag-off", &integer_type, - 16, 13), - [FRAGHDR_RESERVED2] = PAYLOAD_TEMPLATE("reserved2", &integer_type, - 29, 2), - [FRAGHDR_MFRAGS] = PAYLOAD_TEMPLATE("more-fragments", &integer_type, - 31, 1), + [FRAGHDR_FRAG_OFF] = PROTO_HDR_TEMPLATE("frag-off", &integer_type, + 16, 13), + [FRAGHDR_RESERVED2] = PROTO_HDR_TEMPLATE("reserved2", &integer_type, + 29, 2), + [FRAGHDR_MFRAGS] = PROTO_HDR_TEMPLATE("more-fragments", &integer_type, + 31, 1), [FRAGHDR_ID] = FRAG_FIELD("id", ip6f_ident, &integer_type), }, }; @@ -341,6 +341,35 @@ static void meta_expr_clone(struct expr *new, const struct expr *expr) new->meta.key = expr->meta.key; } +/** + * meta_expr_pctx_update - update protocol context based on meta match + * + * @ctx: protocol context + * @expr: relational meta expression + * + * Update LL protocol context based on IIFTYPE meta match in non-LL hooks. + */ +void meta_expr_pctx_update(struct proto_ctx *ctx, const struct expr *expr) +{ + const struct hook_proto_desc *h = &hook_proto_desc[ctx->family]; + const struct expr *left = expr->left, *right = expr->right; + const struct proto_desc *desc; + + if (left->meta.key != NFT_META_IIFTYPE) + return; + + assert(expr->op == OP_EQ); + if (h->base < PROTO_BASE_NETWORK_HDR) + return; + + desc = proto_dev_desc(mpz_get_uint16(right->value)); + if (desc == NULL) + desc = &proto_unknown; + + ctx->protocol[PROTO_BASE_LL_HDR].location = expr->location; + ctx->protocol[PROTO_BASE_LL_HDR].desc = desc; +} + static const struct expr_ops meta_expr_ops = { .type = EXPR_META, .name = "meta", diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 85452735..982377f8 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -573,8 +573,8 @@ static int netlink_parse_expr(struct nft_rule_expr *nle, void *arg) } struct rule_pp_ctx { - struct payload_ctx pctx; - enum payload_bases pbase; + struct proto_ctx pctx; + enum proto_bases pbase; struct stmt *pdep; }; @@ -583,7 +583,7 @@ struct rule_pp_ctx { */ static void payload_dependency_kill(struct rule_pp_ctx *ctx, struct expr *expr) { - if (ctx->pbase != PAYLOAD_BASE_INVALID && + if (ctx->pbase != PROTO_BASE_INVALID && ctx->pbase == expr->payload.base - 1 && ctx->pdep != NULL) { list_del(&ctx->pdep->list); @@ -612,7 +612,7 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx, nexpr = relational_expr_alloc(&expr->location, expr->op, left, tmp); - payload_ctx_update(&ctx->pctx, nexpr); + payload_expr_pctx_update(&ctx->pctx, nexpr); nstmt = expr_stmt_alloc(&stmt->location, nexpr); list_add_tail(&nstmt->list, &stmt->list); @@ -621,7 +621,7 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx, * kill it later on if made redundant by a higher layer * payload expression. */ - if (ctx->pbase == PAYLOAD_BASE_INVALID && + if (ctx->pbase == PROTO_BASE_INVALID && left->flags & EXPR_F_PROTOCOL) { ctx->pbase = left->payload.base; ctx->pdep = nstmt; @@ -639,12 +639,12 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx, } } -static void meta_match_postprocess(struct payload_ctx *ctx, +static void meta_match_postprocess(struct proto_ctx *ctx, const struct expr *expr) { switch (expr->op) { case OP_EQ: - payload_ctx_update_meta(ctx, expr); + meta_expr_pctx_update(ctx, expr); break; default: break; @@ -821,7 +821,7 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r struct stmt *stmt, *next; memset(&rctx, 0, sizeof(rctx)); - payload_ctx_init(&rctx.pctx, rule->handle.family); + proto_ctx_init(&rctx.pctx, rule->handle.family); list_for_each_entry_safe(stmt, next, &rule->stmts, list) { switch (stmt->ops->type) { diff --git a/src/parser.y b/src/parser.y index 9320f2dd..7778d504 100644 --- a/src/parser.y +++ b/src/parser.y @@ -1444,14 +1444,14 @@ payload_raw_expr : AT payload_base_spec COMMA NUM COMMA NUM } ; -payload_base_spec : LL_HDR { $$ = PAYLOAD_BASE_LL_HDR; } - | NETWORK_HDR { $$ = PAYLOAD_BASE_NETWORK_HDR; } - | TRANSPORT_HDR { $$ = PAYLOAD_BASE_TRANSPORT_HDR; } +payload_base_spec : LL_HDR { $$ = PROTO_BASE_LL_HDR; } + | NETWORK_HDR { $$ = PROTO_BASE_NETWORK_HDR; } + | TRANSPORT_HDR { $$ = PROTO_BASE_TRANSPORT_HDR; } ; eth_hdr_expr : ETH eth_hdr_field { - $$ = payload_expr_alloc(&@$, &payload_eth, $2); + $$ = payload_expr_alloc(&@$, &proto_eth, $2); } ; @@ -1462,7 +1462,7 @@ eth_hdr_field : SADDR { $$ = ETHHDR_SADDR; } vlan_hdr_expr : VLAN vlan_hdr_field { - $$ = payload_expr_alloc(&@$, &payload_vlan, $2); + $$ = payload_expr_alloc(&@$, &proto_vlan, $2); } ; @@ -1474,7 +1474,7 @@ vlan_hdr_field : ID { $$ = VLANHDR_VID; } arp_hdr_expr : ARP arp_hdr_field { - $$ = payload_expr_alloc(&@$, &payload_arp, $2); + $$ = payload_expr_alloc(&@$, &proto_arp, $2); } ; @@ -1487,7 +1487,7 @@ arp_hdr_field : HTYPE { $$ = ARPHDR_HRD; } ip_hdr_expr : IP ip_hdr_field { - $$ = payload_expr_alloc(&@$, &payload_ip, $2); + $$ = payload_expr_alloc(&@$, &proto_ip, $2); } ; @@ -1506,7 +1506,7 @@ ip_hdr_field : VERSION { $$ = IPHDR_VERSION; } icmp_hdr_expr : ICMP icmp_hdr_field { - $$ = payload_expr_alloc(&@$, &payload_icmp, $2); + $$ = payload_expr_alloc(&@$, &proto_icmp, $2); } | ICMP { @@ -1528,7 +1528,7 @@ icmp_hdr_field : TYPE { $$ = ICMPHDR_TYPE; } ip6_hdr_expr : IP6 ip6_hdr_field { - $$ = payload_expr_alloc(&@$, &payload_ip6, $2); + $$ = payload_expr_alloc(&@$, &proto_ip6, $2); } ; @@ -1543,7 +1543,7 @@ ip6_hdr_field : VERSION { $$ = IP6HDR_VERSION; } ; icmp6_hdr_expr : ICMP6 icmp6_hdr_field { - $$ = payload_expr_alloc(&@$, &payload_icmp6, $2); + $$ = payload_expr_alloc(&@$, &proto_icmp6, $2); } | ICMP6 { @@ -1566,7 +1566,7 @@ icmp6_hdr_field : TYPE { $$ = ICMP6HDR_TYPE; } auth_hdr_expr : AH auth_hdr_field { - $$ = payload_expr_alloc(&@$, &payload_ah, $2); + $$ = payload_expr_alloc(&@$, &proto_ah, $2); } | AH { @@ -1586,7 +1586,7 @@ auth_hdr_field : NEXTHDR { $$ = AHHDR_NEXTHDR; } esp_hdr_expr : ESP esp_hdr_field { - $$ = payload_expr_alloc(&@$, &payload_esp, $2); + $$ = payload_expr_alloc(&@$, &proto_esp, $2); } | ESP { @@ -1603,7 +1603,7 @@ esp_hdr_field : SPI { $$ = ESPHDR_SPI; } comp_hdr_expr : COMP comp_hdr_field { - $$ = payload_expr_alloc(&@$, &payload_comp, $2); + $$ = payload_expr_alloc(&@$, &proto_comp, $2); } | COMP { @@ -1621,7 +1621,7 @@ comp_hdr_field : NEXTHDR { $$ = COMPHDR_NEXTHDR; } udp_hdr_expr : UDP udp_hdr_field { - $$ = payload_expr_alloc(&@$, &payload_udp, $2); + $$ = payload_expr_alloc(&@$, &proto_udp, $2); } | UDP { @@ -1640,7 +1640,7 @@ udp_hdr_field : SPORT { $$ = UDPHDR_SPORT; } udplite_hdr_expr : UDPLITE udplite_hdr_field { - $$ = payload_expr_alloc(&@$, &payload_udplite, $2); + $$ = payload_expr_alloc(&@$, &proto_udplite, $2); } | UDPLITE { @@ -1659,7 +1659,7 @@ udplite_hdr_field : SPORT { $$ = UDPHDR_SPORT; } tcp_hdr_expr : TCP tcp_hdr_field { - $$ = payload_expr_alloc(&@$, &payload_tcp, $2); + $$ = payload_expr_alloc(&@$, &proto_tcp, $2); } | TCP { @@ -1684,7 +1684,7 @@ tcp_hdr_field : SPORT { $$ = TCPHDR_SPORT; } dccp_hdr_expr : DCCP dccp_hdr_field { - $$ = payload_expr_alloc(&@$, &payload_dccp, $2); + $$ = payload_expr_alloc(&@$, &proto_dccp, $2); } | DCCP { @@ -1702,7 +1702,7 @@ dccp_hdr_field : SPORT { $$ = DCCPHDR_SPORT; } sctp_hdr_expr : SCTP sctp_hdr_field { - $$ = payload_expr_alloc(&@$, &payload_sctp, $2); + $$ = payload_expr_alloc(&@$, &proto_sctp, $2); } | SCTP { diff --git a/src/payload.c b/src/payload.c index 2a60a762..7721b755 100644 --- a/src/payload.c +++ b/src/payload.c @@ -1,5 +1,5 @@ /* - * Payload expression protocol and type definitions and related functions. + * Payload expression and related functions. * * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> * @@ -22,36 +22,13 @@ #include <rule.h> #include <expression.h> #include <payload.h> -#include <headers.h> #include <gmputil.h> #include <utils.h> -static const char *payload_base_names[] = { - [PAYLOAD_BASE_INVALID] = "invalid", - [PAYLOAD_BASE_LL_HDR] = "link layer", - [PAYLOAD_BASE_NETWORK_HDR] = "network layer", - [PAYLOAD_BASE_TRANSPORT_HDR] = "transport layer", -}; - -static const char *payload_base_tokens[] = { - [PAYLOAD_BASE_INVALID] = "invalid", - [PAYLOAD_BASE_LL_HDR] = "ll", - [PAYLOAD_BASE_NETWORK_HDR] = "nh", - [PAYLOAD_BASE_TRANSPORT_HDR] = "th", -}; - -static const struct payload_template payload_unknown_template = - PAYLOAD_TEMPLATE("unknown", &invalid_type, 0, 0); - -static const struct payload_desc payload_unknown_desc = { - .name = "unknown", - .base = PAYLOAD_BASE_INVALID, -}; - static void payload_expr_print(const struct expr *expr) { - const struct payload_desc *desc; - const struct payload_template *tmpl; + const struct proto_desc *desc; + const struct proto_hdr_template *tmpl; desc = expr->payload.desc; tmpl = expr->payload.tmpl; @@ -59,7 +36,7 @@ static void payload_expr_print(const struct expr *expr) printf("%s %s", desc->name, tmpl->token); else printf("payload @%s,%u,%u", - payload_base_tokens[expr->payload.base], + proto_base_tokens[expr->payload.base], expr->payload.offset, expr->len); } @@ -79,11 +56,11 @@ static const struct expr_ops payload_expr_ops = { }; struct expr *payload_expr_alloc(const struct location *loc, - const struct payload_desc *desc, + const struct proto_desc *desc, unsigned int type) { - const struct payload_template *tmpl; - enum payload_bases base; + const struct proto_hdr_template *tmpl; + enum proto_bases base; struct expr *expr; unsigned int flags = 0; @@ -93,8 +70,8 @@ struct expr *payload_expr_alloc(const struct location *loc, if (type == desc->protocol_key) flags = EXPR_F_PROTOCOL; } else { - tmpl = &payload_unknown_template; - base = PAYLOAD_BASE_INVALID; + tmpl = &proto_unknown_template; + base = PROTO_BASE_INVALID; } expr = expr_alloc(loc, &payload_expr_ops, tmpl->dtype, @@ -109,7 +86,7 @@ struct expr *payload_expr_alloc(const struct location *loc, return expr; } -void payload_init_raw(struct expr *expr, enum payload_bases base, +void payload_init_raw(struct expr *expr, enum proto_bases base, unsigned int offset, unsigned int len) { expr->payload.base = base; @@ -118,151 +95,24 @@ void payload_init_raw(struct expr *expr, enum payload_bases base, } /** - * payload_select_proto - find protocol description by protocol value linking - * it to lower layer protocol - * - * @base: lower layer protocol description - * @num: protocol value - */ -static const struct payload_desc * -payload_select_proto(const struct payload_desc *base, unsigned int num) -{ - unsigned int i; - - for (i = 0; i < array_size(base->protocols); i++) { - if (base->protocols[i].num == num) - return base->protocols[i].desc; - } - return NULL; -} - -/** - * payload_proto_val - return protocol number linking two protocols together - * - * @base: lower layer protocol description - * @desc: upper layer protocol description - */ -static int payload_proto_val(const struct payload_desc *base, - const struct payload_desc *desc) -{ - unsigned int i; - - for (i = 0; i < array_size(base->protocols); i++) { - if (base->protocols[i].desc == desc) - return base->protocols[i].num; - } - return -1; -} - -static const struct dev_payload_desc dev_payload_desc[] = { - DEV_PAYLOAD_DESC(ARPHRD_ETHER, &payload_eth), -}; - -/** - * payload_dev_type - return arphrd type linking a device and a protocol together - * - * @desc: the protocol description - * @res: pointer to result - */ -static int payload_dev_type(const struct payload_desc *desc, uint16_t *res) -{ - unsigned int i; - - for (i = 0; i < array_size(dev_payload_desc); i++) { - if (dev_payload_desc[i].desc == desc) { - *res = dev_payload_desc[i].type; - return 0; - } - } - return -1; -} - -/** - * payload_dev_desc - return protocol description for an arphrd type - * - * @type: the arphrd type - */ -static const struct payload_desc *payload_dev_desc(uint16_t type) -{ - unsigned int i; - - for (i = 0; i < array_size(dev_payload_desc); i++) { - if (dev_payload_desc[i].type == type) - return dev_payload_desc[i].desc; - } - return NULL; -} - -static const struct payload_hook_desc payload_hooks[] = { - [NFPROTO_BRIDGE] = PAYLOAD_HOOK(PAYLOAD_BASE_LL_HDR, &payload_eth), - [NFPROTO_IPV4] = PAYLOAD_HOOK(PAYLOAD_BASE_NETWORK_HDR, &payload_ip), - [NFPROTO_IPV6] = PAYLOAD_HOOK(PAYLOAD_BASE_NETWORK_HDR, &payload_ip6), - [NFPROTO_ARP] = PAYLOAD_HOOK(PAYLOAD_BASE_NETWORK_HDR, &payload_arp), -}; - -/** - * payload_ctx_init - initialize payload context for a given hook family - * - * @ctx: payload context - * @family: hook family - */ -void payload_ctx_init(struct payload_ctx *ctx, unsigned int family) -{ - const struct payload_hook_desc *h = &payload_hooks[family]; - - memset(ctx, 0, sizeof(*ctx)); - ctx->family = family; - ctx->protocol[h->base].desc = h->desc; -} - -/** - * payload_ctx_update_meta - update payload context with meta expression - * - * @ctx: payload context - * @expr: relational meta expression - * - * Update LL payload context based on IIFTYPE meta match in non-LL hooks. - */ -void payload_ctx_update_meta(struct payload_ctx *ctx, const struct expr *expr) -{ - const struct payload_hook_desc *h = &payload_hooks[ctx->family]; - const struct expr *left = expr->left, *right = expr->right; - const struct payload_desc *desc; - - if (left->meta.key != NFT_META_IIFTYPE) - return; - - assert(expr->op == OP_EQ); - if (h->base < PAYLOAD_BASE_NETWORK_HDR) - return; - - desc = payload_dev_desc(mpz_get_uint16(right->value)); - if (desc == NULL) - desc = &payload_unknown_desc; - - ctx->protocol[PAYLOAD_BASE_LL_HDR].location = expr->location; - ctx->protocol[PAYLOAD_BASE_LL_HDR].desc = desc; -} - -/** - * payload_ctx_update - update payload context + * payload_expr_pctx_update - update protocol context based on payload match * - * @ctx: payload context + * @ctx: protocol context * @expr: relational payload expression * - * Update payload context for relational payload expressions. + * Update protocol context for relational payload expressions. */ -void payload_ctx_update(struct payload_ctx *ctx, const struct expr *expr) +void payload_expr_pctx_update(struct proto_ctx *ctx, const struct expr *expr) { const struct expr *left = expr->left, *right = expr->right; - const struct payload_desc *base, *desc; + const struct proto_desc *base, *desc; if (!(left->flags & EXPR_F_PROTOCOL)) return; assert(expr->op == OP_EQ); base = ctx->protocol[left->payload.base].desc; - desc = payload_select_proto(base, mpz_get_uint32(right->value)); + desc = proto_find_upper(base, mpz_get_uint32(right->value)); ctx->protocol[left->payload.base + 1].location = expr->location; ctx->protocol[left->payload.base + 1].desc = desc; @@ -294,9 +144,9 @@ void payload_ctx_update(struct payload_ctx *ctx, const struct expr *expr) int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr, struct expr **res) { - const struct payload_hook_desc *h = &payload_hooks[ctx->pctx.family]; - const struct payload_desc *desc; - const struct payload_template *tmpl; + const struct hook_proto_desc *h = &hook_proto_desc[ctx->pctx.family]; + const struct proto_desc *desc; + const struct proto_hdr_template *tmpl; struct expr *dep, *left, *right; int protocol; uint16_t type; @@ -307,7 +157,7 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr, "payload base is invalid for this " "family"); - if (payload_dev_type(expr->payload.desc, &type) < 0) + if (proto_dev_type(expr->payload.desc, &type) < 0) return expr_error(ctx, expr, "protocol specification is invalid " "for this family"); @@ -327,9 +177,9 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr, return expr_error(ctx, expr, "ambiguous payload specification: " "no %s protocol specified", - payload_base_names[expr->payload.base - 1]); + proto_base_names[expr->payload.base - 1]); - protocol = payload_proto_val(desc, expr->payload.desc); + protocol = proto_find_num(desc, expr->payload.desc); if (protocol < 0) return expr_error(ctx, expr, "conflicting protocols specified: %s vs. %s", @@ -342,7 +192,7 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr, tmpl->len, &protocol); dep = relational_expr_alloc(&expr->location, OP_EQ, left, right); - payload_ctx_update(&ctx->pctx, dep); + payload_expr_pctx_update(&ctx->pctx, dep); *res = dep; return 0; } @@ -351,15 +201,15 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr, * payload_expr_complete - fill in type information of a raw payload expr * * @expr: the payload expression - * @ctx: payload context + * @ctx: protocol context * * Complete the type of a raw payload expression based on the context. If * insufficient information is available the expression remains unchanged. */ -void payload_expr_complete(struct expr *expr, const struct payload_ctx *ctx) +void payload_expr_complete(struct expr *expr, const struct proto_ctx *ctx) { - const struct payload_desc *desc; - const struct payload_template *tmpl; + const struct proto_desc *desc; + const struct proto_hdr_template *tmpl; unsigned int i; assert(expr->ops->type == EXPR_PAYLOAD); @@ -387,7 +237,7 @@ void payload_expr_complete(struct expr *expr, const struct payload_ctx *ctx) * * @list: list to append expanded payload expressions to * @expr: the payload expression to expand - * @ctx: payload context + * @ctx: protocol context * * Expand a merged adjacent payload expression into its original components * by splitting elements off the beginning matching a payload template. @@ -396,10 +246,10 @@ void payload_expr_complete(struct expr *expr, const struct payload_ctx *ctx) * offset order. */ void payload_expr_expand(struct list_head *list, struct expr *expr, - const struct payload_ctx *ctx) + const struct proto_ctx *ctx) { - const struct payload_desc *desc; - const struct payload_template *tmpl; + const struct proto_desc *desc; + const struct proto_hdr_template *tmpl; struct expr *new; unsigned int i; @@ -465,590 +315,3 @@ struct expr *payload_expr_join(const struct expr *e1, const struct expr *e2) expr->len = e1->len + e2->len; return expr; } - -#define HDR_TEMPLATE(__name, __dtype, __type, __member) \ - PAYLOAD_TEMPLATE(__name, __dtype, \ - offsetof(__type, __member) * 8, \ - field_sizeof(__type, __member) * 8) - -#define HDR_FIELD(__name, __struct, __member) \ - HDR_TEMPLATE(__name, &integer_type, __struct, __member) -#define HDR_BITFIELD(__name, __dtype, __offset, __len) \ - PAYLOAD_TEMPLATE(__name, __dtype, __offset, __len) -#define HDR_TYPE(__name, __dtype, __struct, __member) \ - HDR_TEMPLATE(__name, __dtype, __struct, __member) - -#define INET_PROTOCOL(__name, __struct, __member) \ - HDR_TYPE(__name, &inet_protocol_type, __struct, __member) -#define INET_SERVICE(__name, __struct, __member) \ - HDR_TYPE(__name, &inet_service_type, __struct, __member) - -/* - * AH - */ - -#define AHHDR_FIELD(__name, __member) \ - HDR_FIELD(__name, struct ip_auth_hdr, __member) - -const struct payload_desc payload_ah = { - .name = "ah", - .base = PAYLOAD_BASE_TRANSPORT_HDR, - .protocol_key = AHHDR_NEXTHDR, - .protocols = { - PAYLOAD_PROTO(IPPROTO_ESP, &payload_esp), - PAYLOAD_PROTO(IPPROTO_AH, &payload_ah), - PAYLOAD_PROTO(IPPROTO_COMP, &payload_comp), - PAYLOAD_PROTO(IPPROTO_UDP, &payload_udp), - PAYLOAD_PROTO(IPPROTO_UDPLITE, &payload_udplite), - PAYLOAD_PROTO(IPPROTO_TCP, &payload_tcp), - PAYLOAD_PROTO(IPPROTO_DCCP, &payload_dccp), - PAYLOAD_PROTO(IPPROTO_SCTP, &payload_sctp), - }, - .templates = { - [AHHDR_NEXTHDR] = INET_PROTOCOL("nexthdr", struct ip_auth_hdr, nexthdr), - [AHHDR_HDRLENGTH] = AHHDR_FIELD("hdrlength", hdrlen), - [AHHDR_RESERVED] = AHHDR_FIELD("reserved", reserved), - [AHHDR_SPI] = AHHDR_FIELD("spi", spi), - [AHHDR_SEQUENCE] = AHHDR_FIELD("sequence", seq_no), - }, -}; - -/* - * ESP - */ - -#define ESPHDR_FIELD(__name, __member) \ - HDR_FIELD(__name, struct ip_esp_hdr, __member) - -const struct payload_desc payload_esp = { - .name = "esp", - .base = PAYLOAD_BASE_TRANSPORT_HDR, - .templates = { - [ESPHDR_SPI] = ESPHDR_FIELD("spi", spi), - [ESPHDR_SEQUENCE] = ESPHDR_FIELD("sequence", seq_no), - }, -}; - -/* - * IPCOMP - */ - -#define COMPHDR_FIELD(__name, __member) \ - HDR_FIELD(__name, struct ip_comp_hdr, __member) - -const struct payload_desc payload_comp = { - .name = "comp", - .base = PAYLOAD_BASE_TRANSPORT_HDR, - .protocol_key = COMPHDR_NEXTHDR, - .protocols = { - PAYLOAD_PROTO(IPPROTO_ESP, &payload_esp), - PAYLOAD_PROTO(IPPROTO_AH, &payload_ah), - PAYLOAD_PROTO(IPPROTO_COMP, &payload_comp), - PAYLOAD_PROTO(IPPROTO_UDP, &payload_udp), - PAYLOAD_PROTO(IPPROTO_UDPLITE, &payload_udplite), - PAYLOAD_PROTO(IPPROTO_TCP, &payload_tcp), - PAYLOAD_PROTO(IPPROTO_DCCP, &payload_dccp), - PAYLOAD_PROTO(IPPROTO_SCTP, &payload_sctp), - }, - .templates = { - [COMPHDR_NEXTHDR] = INET_PROTOCOL("nexthdr", struct ip_comp_hdr, nexthdr), - [COMPHDR_FLAGS] = COMPHDR_FIELD("flags", flags), - [COMPHDR_CPI] = COMPHDR_FIELD("cpi", cpi), - }, -}; - -/* - * ICMP - */ - -#include <netinet/ip_icmp.h> - -static const struct symbol_table icmp_type_tbl = { - .symbols = { - SYMBOL("echo-reply", ICMP_ECHOREPLY), - SYMBOL("destination-unreachable", ICMP_DEST_UNREACH), - SYMBOL("source-quench", ICMP_SOURCE_QUENCH), - SYMBOL("redirect", ICMP_REDIRECT), - SYMBOL("echo-request", ICMP_ECHO), - SYMBOL("time-exceeded", ICMP_TIME_EXCEEDED), - SYMBOL("parameter-problem", ICMP_PARAMETERPROB), - SYMBOL("timestamp-request", ICMP_TIMESTAMP), - SYMBOL("timestamp-reply", ICMP_TIMESTAMPREPLY), - SYMBOL("info-request", ICMP_INFO_REQUEST), - SYMBOL("info-reply", ICMP_INFO_REPLY), - SYMBOL("address-mask-request", ICMP_ADDRESS), - SYMBOL("address-mask-reply", ICMP_ADDRESSREPLY), - SYMBOL_LIST_END - }, -}; - -static const struct datatype icmp_type_type = { - .type = TYPE_ICMP_TYPE, - .name = "icmp_type", - .desc = "ICMP type", - .byteorder = BYTEORDER_BIG_ENDIAN, - .size = BITS_PER_BYTE, - .basetype = &integer_type, - .sym_tbl = &icmp_type_tbl, -}; - -#define ICMPHDR_FIELD(__name, __member) \ - HDR_FIELD(__name, struct icmphdr, __member) -#define ICMPHDR_TYPE(__name, __type, __member) \ - HDR_TYPE(__name, __type, struct icmphdr, __member) - -const struct payload_desc payload_icmp = { - .name = "icmp", - .base = PAYLOAD_BASE_TRANSPORT_HDR, - .templates = { - [ICMPHDR_TYPE] = ICMPHDR_TYPE("type", &icmp_type_type, type), - [ICMPHDR_CODE] = ICMPHDR_FIELD("code", code), - [ICMPHDR_CHECKSUM] = ICMPHDR_FIELD("checksum", checksum), - [ICMPHDR_ID] = ICMPHDR_FIELD("id", un.echo.id), - [ICMPHDR_SEQ] = ICMPHDR_FIELD("sequence", un.echo.sequence), - [ICMPHDR_GATEWAY] = ICMPHDR_FIELD("gateway", un.gateway), - [ICMPHDR_MTU] = ICMPHDR_FIELD("mtu", un.frag.mtu), - }, -}; - -/* - * UDP/UDP-Lite - */ - -#include <netinet/udp.h> -#define UDPHDR_FIELD(__name, __member) \ - HDR_FIELD(__name, struct udphdr, __member) - -const struct payload_desc payload_udp = { - .name = "udp", - .base = PAYLOAD_BASE_TRANSPORT_HDR, - .templates = { - [UDPHDR_SPORT] = INET_SERVICE("sport", struct udphdr, source), - [UDPHDR_DPORT] = INET_SERVICE("dport", struct udphdr, dest), - [UDPHDR_LENGTH] = UDPHDR_FIELD("length", len), - [UDPHDR_CHECKSUM] = UDPHDR_FIELD("checksum", check), - }, -}; - -const struct payload_desc payload_udplite = { - .name = "udplite", - .base = PAYLOAD_BASE_TRANSPORT_HDR, - .templates = { - [UDPHDR_SPORT] = INET_SERVICE("sport", struct udphdr, source), - [UDPHDR_DPORT] = INET_SERVICE("dport", struct udphdr, dest), - [UDPHDR_CSUMCOV] = UDPHDR_FIELD("csumcov", len), - [UDPHDR_CHECKSUM] = UDPHDR_FIELD("checksum", check), - }, -}; - -/* - * TCP - */ - -#include <netinet/tcp.h> - -static const struct symbol_table tcp_flag_tbl = { - .symbols = { - SYMBOL("fin", TCP_FLAG_FIN), - SYMBOL("syn", TCP_FLAG_SYN), - SYMBOL("rst", TCP_FLAG_RST), - SYMBOL("psh", TCP_FLAG_PSH), - SYMBOL("ack", TCP_FLAG_ACK), - SYMBOL("urg", TCP_FLAG_URG), - SYMBOL("ecn", TCP_FLAG_ECN), - SYMBOL("cwr", TCP_FLAG_CWR), - SYMBOL_LIST_END - }, -}; - -static const struct datatype tcp_flag_type = { - .type = TYPE_TCP_FLAG, - .name = "tcp_flag", - .desc = "TCP flag", - .byteorder = BYTEORDER_BIG_ENDIAN, - .size = BITS_PER_BYTE, - .basetype = &bitmask_type, - .sym_tbl = &tcp_flag_tbl, -}; - -#define TCPHDR_FIELD(__name, __member) \ - HDR_FIELD(__name, struct tcphdr, __member) - -const struct payload_desc payload_tcp = { - .name = "tcp", - .base = PAYLOAD_BASE_TRANSPORT_HDR, - .templates = { - [TCPHDR_SPORT] = INET_SERVICE("sport", struct tcphdr, source), - [TCPHDR_DPORT] = INET_SERVICE("dport", struct tcphdr, dest), - [TCPHDR_SEQ] = TCPHDR_FIELD("sequence", seq), - [TCPHDR_ACKSEQ] = TCPHDR_FIELD("ackseq", ack_seq), - [TCPHDR_DOFF] = {}, - [TCPHDR_RESERVED] = {}, - [TCPHDR_FLAGS] = HDR_BITFIELD("flags", &tcp_flag_type, - 13 * BITS_PER_BYTE, - BITS_PER_BYTE), - [TCPHDR_WINDOW] = TCPHDR_FIELD("window", window), - [TCPHDR_CHECKSUM] = TCPHDR_FIELD("checksum", check), - [TCPHDR_URGPTR] = TCPHDR_FIELD("urgptr", urg_ptr), - }, -}; - -/* - * DCCP - */ - -static const struct symbol_table dccp_pkttype_tbl = { - .symbols = { - SYMBOL("request", DCCP_PKT_REQUEST), - SYMBOL("response", DCCP_PKT_RESPONSE), - SYMBOL("data", DCCP_PKT_DATA), - SYMBOL("ack", DCCP_PKT_ACK), - SYMBOL("dataack", DCCP_PKT_DATAACK), - SYMBOL("closereq", DCCP_PKT_CLOSEREQ), - SYMBOL("close", DCCP_PKT_CLOSE), - SYMBOL("reset", DCCP_PKT_RESET), - SYMBOL("sync", DCCP_PKT_SYNC), - SYMBOL("syncack", DCCP_PKT_SYNCACK), - SYMBOL_LIST_END - }, -}; - -static const struct datatype dccp_pkttype_type = { - .type = TYPE_DCCP_PKTTYPE, - .name = "dccp_pkttype", - .desc = "DCCP packet type", - .byteorder = BYTEORDER_INVALID, - .size = 4, - .basetype = &integer_type, - .sym_tbl = &dccp_pkttype_tbl, -}; - - -#define DCCPHDR_FIELD(__name, __member) \ - HDR_FIELD(__name, struct dccp_hdr, __member) - -const struct payload_desc payload_dccp = { - .name = "dccp", - .base = PAYLOAD_BASE_TRANSPORT_HDR, - .templates = { - [DCCPHDR_SPORT] = INET_SERVICE("sport", struct dccp_hdr, dccph_sport), - [DCCPHDR_DPORT] = INET_SERVICE("dport", struct dccp_hdr, dccph_dport), - [DCCPHDR_TYPE] = HDR_BITFIELD("type", &dccp_pkttype_type, 67, 4), - }, -}; - -/* - * SCTP - */ - -#define SCTPHDR_FIELD(__name, __member) \ - HDR_FIELD(__name, struct sctphdr, __member) - -const struct payload_desc payload_sctp = { - .name = "sctp", - .base = PAYLOAD_BASE_TRANSPORT_HDR, - .templates = { - [SCTPHDR_SPORT] = INET_SERVICE("sport", struct sctphdr, source), - [SCTPHDR_DPORT] = INET_SERVICE("dport", struct sctphdr, dest), - [SCTPHDR_VTAG] = SCTPHDR_FIELD("vtag", vtag), - [SCTPHDR_CHECKSUM] = SCTPHDR_FIELD("checksum", checksum), - }, -}; - -/* - * IPv4 - */ - -#include <netinet/ip.h> -#define IPHDR_FIELD(__name, __member) \ - HDR_FIELD(__name, struct iphdr, __member) -#define IPHDR_ADDR(__name, __member) \ - HDR_TYPE(__name, &ipaddr_type, struct iphdr, __member) - -const struct payload_desc payload_ip = { - .name = "ip", - .base = PAYLOAD_BASE_NETWORK_HDR, - .protocol_key = IPHDR_PROTOCOL, - .protocols = { - PAYLOAD_PROTO(IPPROTO_ICMP, &payload_icmp), - PAYLOAD_PROTO(IPPROTO_ESP, &payload_esp), - PAYLOAD_PROTO(IPPROTO_AH, &payload_ah), - PAYLOAD_PROTO(IPPROTO_COMP, &payload_comp), - PAYLOAD_PROTO(IPPROTO_UDP, &payload_udp), - PAYLOAD_PROTO(IPPROTO_UDPLITE, &payload_udplite), - PAYLOAD_PROTO(IPPROTO_TCP, &payload_tcp), - PAYLOAD_PROTO(IPPROTO_DCCP, &payload_dccp), - PAYLOAD_PROTO(IPPROTO_SCTP, &payload_sctp), - }, - .templates = { - [IPHDR_VERSION] = HDR_BITFIELD("version", &integer_type, 0, 4), - [IPHDR_HDRLENGTH] = HDR_BITFIELD("hdrlength", &integer_type, 4, 4), - [IPHDR_TOS] = IPHDR_FIELD("tos", tos), - [IPHDR_LENGTH] = IPHDR_FIELD("length", tot_len), - [IPHDR_ID] = IPHDR_FIELD("id", id), - [IPHDR_FRAG_OFF] = IPHDR_FIELD("frag-off", frag_off), - [IPHDR_TTL] = IPHDR_FIELD("ttl", ttl), - [IPHDR_PROTOCOL] = INET_PROTOCOL("protocol", struct iphdr, protocol), - [IPHDR_CHECKSUM] = IPHDR_FIELD("checksum", check), - [IPHDR_SADDR] = IPHDR_ADDR("saddr", saddr), - [IPHDR_DADDR] = IPHDR_ADDR("daddr", daddr), - }, -}; - -/* - * ICMPv6 - */ - -#include <netinet/icmp6.h> - -static const struct symbol_table icmp6_type_tbl = { - .symbols = { - SYMBOL("destination-unreachable", ICMP6_DST_UNREACH), - SYMBOL("packet-too-big", ICMP6_PACKET_TOO_BIG), - SYMBOL("time-exceeded", ICMP6_TIME_EXCEEDED), - SYMBOL("param-problem", ICMP6_PARAM_PROB), - SYMBOL("echo-request", ICMP6_ECHO_REQUEST), - SYMBOL("echo-reply", ICMP6_ECHO_REPLY), - SYMBOL("mld-listener-query", MLD_LISTENER_QUERY), - SYMBOL("mld-listener-report", MLD_LISTENER_REPORT), - SYMBOL("mld-listener-reduction", MLD_LISTENER_REDUCTION), - SYMBOL("nd-router-solicit", ND_ROUTER_SOLICIT), - SYMBOL("nd-router-advert", ND_ROUTER_ADVERT), - SYMBOL("nd-neighbor-solicit", ND_NEIGHBOR_SOLICIT), - SYMBOL("nd-neighbor-advert", ND_NEIGHBOR_ADVERT), - SYMBOL("nd-redirect", ND_REDIRECT), - SYMBOL("router-renumbering", ICMP6_ROUTER_RENUMBERING), - SYMBOL_LIST_END - }, -}; - -static const struct datatype icmp6_type_type = { - .type = TYPE_ICMP6_TYPE, - .name = "icmpv6_type", - .desc = "ICMPv6 type", - .byteorder = BYTEORDER_BIG_ENDIAN, - .size = BITS_PER_BYTE, - .basetype = &integer_type, - .sym_tbl = &icmp6_type_tbl, -}; - -#define ICMP6HDR_FIELD(__name, __member) \ - HDR_FIELD(__name, struct icmp6_hdr, __member) -#define ICMP6HDR_TYPE(__name, __type, __member) \ - HDR_TYPE(__name, __type, struct icmp6_hdr, __member) - -const struct payload_desc payload_icmp6 = { - .name = "icmpv6", - .base = PAYLOAD_BASE_TRANSPORT_HDR, - .templates = { - [ICMP6HDR_TYPE] = ICMP6HDR_TYPE("type", &icmp6_type_type, icmp6_type), - [ICMP6HDR_CODE] = ICMP6HDR_FIELD("code", icmp6_code), - [ICMP6HDR_CHECKSUM] = ICMP6HDR_FIELD("checksum", icmp6_cksum), - [ICMP6HDR_PPTR] = ICMP6HDR_FIELD("parameter-problem", icmp6_pptr), - [ICMP6HDR_MTU] = ICMP6HDR_FIELD("packet-too-big", icmp6_mtu), - [ICMP6HDR_ID] = ICMP6HDR_FIELD("id", icmp6_id), - [ICMP6HDR_SEQ] = ICMP6HDR_FIELD("sequence", icmp6_seq), - [ICMP6HDR_MAXDELAY] = ICMP6HDR_FIELD("max-delay", icmp6_maxdelay), - }, -}; - -/* - * IPv6 - */ - -#define IP6HDR_FIELD(__name, __member) \ - HDR_FIELD(__name, struct ipv6hdr, __member) -#define IP6HDR_ADDR(__name, __member) \ - HDR_TYPE(__name, &ip6addr_type, struct ipv6hdr, __member) -#define IP6HDR_PROTOCOL(__name, __member) \ - HDR_TYPE(__name, &inet_service_type, struct ipv6hdr, __member) - -const struct payload_desc payload_ip6 = { - .name = "ip6", - .base = PAYLOAD_BASE_NETWORK_HDR, - .protocol_key = IP6HDR_NEXTHDR, - .protocols = { - PAYLOAD_PROTO(IPPROTO_ESP, &payload_esp), - PAYLOAD_PROTO(IPPROTO_AH, &payload_ah), - PAYLOAD_PROTO(IPPROTO_COMP, &payload_comp), - PAYLOAD_PROTO(IPPROTO_UDP, &payload_udp), - PAYLOAD_PROTO(IPPROTO_UDPLITE, &payload_udplite), - PAYLOAD_PROTO(IPPROTO_TCP, &payload_tcp), - PAYLOAD_PROTO(IPPROTO_DCCP, &payload_dccp), - PAYLOAD_PROTO(IPPROTO_SCTP, &payload_sctp), - PAYLOAD_PROTO(IPPROTO_ICMPV6, &payload_icmp6), - }, - .templates = { - [IP6HDR_VERSION] = HDR_BITFIELD("version", &integer_type, 0, 4), - [IP6HDR_PRIORITY] = HDR_BITFIELD("priority", &integer_type, 4, 4), - [IP6HDR_FLOWLABEL] = IP6HDR_FIELD("flowlabel", flow_lbl), - [IP6HDR_LENGTH] = IP6HDR_FIELD("length", payload_len), - [IP6HDR_NEXTHDR] = INET_PROTOCOL("nexthdr", struct ipv6hdr, nexthdr), - [IP6HDR_HOPLIMIT] = IP6HDR_FIELD("hoplimit", hop_limit), - [IP6HDR_SADDR] = IP6HDR_ADDR("saddr", saddr), - [IP6HDR_DADDR] = IP6HDR_ADDR("daddr", daddr), - }, -}; - -/* - * ARP - */ - -#include <net/if_arp.h> - -static const struct symbol_table arpop_tbl = { - .symbols = { - SYMBOL("request", ARPOP_REQUEST), - SYMBOL("reply", ARPOP_REPLY), - SYMBOL("rrequest", ARPOP_RREQUEST), - SYMBOL("rreply", ARPOP_REPLY), - SYMBOL("inrequest", ARPOP_InREQUEST), - SYMBOL("inreply", ARPOP_InREPLY), - SYMBOL("nak", ARPOP_NAK), - SYMBOL_LIST_END - }, -}; - -static const struct datatype arpop_type = { - .type = TYPE_ARPOP, - .name = "arp_op", - .desc = "ARP operation", - .byteorder = BYTEORDER_BIG_ENDIAN, - .size = 2 * BITS_PER_BYTE, - .basetype = &integer_type, - .sym_tbl = &arpop_tbl, -}; - -#define ARPHDR_TYPE(__name, __type, __member) \ - HDR_TYPE(__name, __type, struct arphdr, __member) -#define ARPHDR_FIELD(__name, __member) \ - HDR_FIELD(__name, struct arphdr, __member) - -const struct payload_desc payload_arp = { - .name = "arp", - .base = PAYLOAD_BASE_NETWORK_HDR, - .templates = { - [ARPHDR_HRD] = ARPHDR_FIELD("htype", ar_hrd), - [ARPHDR_PRO] = ARPHDR_TYPE("ptype", ðertype_type, ar_pro), - [ARPHDR_HLN] = ARPHDR_FIELD("hlen", ar_hln), - [ARPHDR_PLN] = ARPHDR_FIELD("plen", ar_pln), - [ARPHDR_OP] = ARPHDR_TYPE("operation", &arpop_type, ar_op), - }, -}; - -/* - * VLAN - */ - -#include <net/ethernet.h> - -#define VLANHDR_BITFIELD(__name, __offset, __len) \ - HDR_BITFIELD(__name, &integer_type, __offset, __len) -#define VLANHDR_TYPE(__name, __type, __member) \ - HDR_TYPE(__name, __type, struct vlan_hdr, __member) - -const struct payload_desc payload_vlan = { - .name = "vlan", - .base = PAYLOAD_BASE_LL_HDR, - .protocol_key = VLANHDR_TYPE, - .protocols = { - PAYLOAD_PROTO(ETH_P_IP, &payload_ip), - PAYLOAD_PROTO(ETH_P_ARP, &payload_arp), - PAYLOAD_PROTO(ETH_P_IPV6, &payload_ip6), - PAYLOAD_PROTO(ETH_P_8021Q, &payload_vlan), - - }, - .templates = { - [VLANHDR_VID] = VLANHDR_BITFIELD("id", 0, 12), - [VLANHDR_CFI] = VLANHDR_BITFIELD("cfi", 12, 1), - [VLANHDR_PCP] = VLANHDR_BITFIELD("pcp", 13, 3), - [VLANHDR_TYPE] = VLANHDR_TYPE("type", ðertype_type, vlan_type), - }, -}; - -/* - * Ethernet - */ - -const struct datatype etheraddr_type = { - .type = TYPE_ETHERADDR, - .name = "etheraddr", - .desc = "Ethernet address", - .byteorder = BYTEORDER_HOST_ENDIAN, - .size = ETH_ALEN * BITS_PER_BYTE, - .basetype = &lladdr_type, -}; - -static const struct symbol_table ethertype_tbl = { - .symbols = { - SYMBOL("ip", ETH_P_IP), - SYMBOL("arp", ETH_P_ARP), - SYMBOL("ipv6", ETH_P_IPV6), - SYMBOL("vlan", ETH_P_8021Q), - SYMBOL_LIST_END - }, -}; - -static struct error_record *ethertype_parse(const struct expr *sym, - struct expr **res) -{ - struct error_record *erec; - - erec = sym->dtype->basetype->parse(sym, res); - if (erec != NULL) - return erec; - if (*res) - return NULL; - return symbolic_constant_parse(sym, ðertype_tbl, res); -} - -static void ethertype_print(const struct expr *expr) -{ - return symbolic_constant_print(ðertype_tbl, expr); -} - -const struct datatype ethertype_type = { - .type = TYPE_ETHERTYPE, - .name = "ethertype", - .desc = "Ethernet protocol", - .byteorder = BYTEORDER_BIG_ENDIAN, - .size = 2 * BITS_PER_BYTE, - .basetype = &integer_type, - .basefmt = "0x%.4Zx", - .print = ethertype_print, - .parse = ethertype_parse, -}; - -#define ETHHDR_TEMPLATE(__name, __dtype, __member) \ - HDR_TEMPLATE(__name, __dtype, struct ether_header, __member) -#define ETHHDR_TYPE(__name, __member) \ - ETHHDR_TEMPLATE(__name, ðertype_type, __member) -#define ETHHDR_ADDR(__name, __member) \ - ETHHDR_TEMPLATE(__name, ðeraddr_type, __member) - -const struct payload_desc payload_eth = { - .name = "eth", - .base = PAYLOAD_BASE_LL_HDR, - .protocol_key = ETHHDR_TYPE, - .protocols = { - PAYLOAD_PROTO(ETH_P_IP, &payload_ip), - PAYLOAD_PROTO(ETH_P_ARP, &payload_arp), - PAYLOAD_PROTO(ETH_P_IPV6, &payload_ip6), - PAYLOAD_PROTO(ETH_P_8021Q, &payload_vlan), - }, - .templates = { - [ETHHDR_DADDR] = ETHHDR_ADDR("daddr", ether_dhost), - [ETHHDR_SADDR] = ETHHDR_ADDR("saddr", ether_shost), - [ETHHDR_TYPE] = ETHHDR_TYPE("type", ether_type), - }, -}; - -static void __init payload_init(void) -{ - datatype_register(&icmp_type_type); - datatype_register(&tcp_flag_type); - datatype_register(&dccp_pkttype_type); - datatype_register(&arpop_type); - datatype_register(ðertype_type); - datatype_register(&icmp6_type_type); -} diff --git a/src/proto.c b/src/proto.c new file mode 100644 index 00000000..c6428e4c --- /dev/null +++ b/src/proto.c @@ -0,0 +1,731 @@ +/* + * Protocol header and type definitions and related functions. + * + * Copyright (c) 2014 Patrick McHardy <kaber@trash.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <stddef.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <net/if_arp.h> +#include <arpa/inet.h> +#include <linux/netfilter.h> + +#include <expression.h> +#include <headers.h> +#include <proto.h> +#include <gmputil.h> +#include <utils.h> + +const char *proto_base_names[] = { + [PROTO_BASE_INVALID] = "invalid", + [PROTO_BASE_LL_HDR] = "link layer", + [PROTO_BASE_NETWORK_HDR] = "network layer", + [PROTO_BASE_TRANSPORT_HDR] = "transport layer", +}; + +const char *proto_base_tokens[] = { + [PROTO_BASE_INVALID] = "invalid", + [PROTO_BASE_LL_HDR] = "ll", + [PROTO_BASE_NETWORK_HDR] = "nh", + [PROTO_BASE_TRANSPORT_HDR] = "th", +}; + +const struct proto_hdr_template proto_unknown_template = + PROTO_HDR_TEMPLATE("unknown", &invalid_type, 0, 0); + +const struct proto_desc proto_unknown = { + .name = "unknown", + .base = PROTO_BASE_INVALID, +}; + +/** + * proto_find_upper - find higher layer protocol description by protocol value + * linking it to the lower layer protocol + * + * @base: lower layer protocol description + * @num: protocol value + */ +const struct proto_desc * +proto_find_upper(const struct proto_desc *base, unsigned int num) +{ + unsigned int i; + + for (i = 0; i < array_size(base->protocols); i++) { + if (base->protocols[i].num == num) + return base->protocols[i].desc; + } + return NULL; +} + +/** + * proto_find_num - return protocol number linking two protocols together + * + * @base: lower layer protocol description + * @desc: upper layer protocol description + */ +int proto_find_num(const struct proto_desc *base, + const struct proto_desc *desc) +{ + unsigned int i; + + for (i = 0; i < array_size(base->protocols); i++) { + if (base->protocols[i].desc == desc) + return base->protocols[i].num; + } + return -1; +} + +static const struct dev_proto_desc dev_proto_desc[] = { + DEV_PROTO_DESC(ARPHRD_ETHER, &proto_eth), +}; + +/** + * proto_dev_type - return arphrd type linking a device and a protocol together + * + * @desc: the protocol description + * @res: pointer to result + */ +int proto_dev_type(const struct proto_desc *desc, uint16_t *res) +{ + unsigned int i; + + for (i = 0; i < array_size(dev_proto_desc); i++) { + if (dev_proto_desc[i].desc == desc) { + *res = dev_proto_desc[i].type; + return 0; + } + } + return -1; +} + +/** + * proto_dev_desc - return protocol description for an arphrd type + * + * @type: the arphrd type + */ +const struct proto_desc *proto_dev_desc(uint16_t type) +{ + unsigned int i; + + for (i = 0; i < array_size(dev_proto_desc); i++) { + if (dev_proto_desc[i].type == type) + return dev_proto_desc[i].desc; + } + return NULL; +} + +const struct hook_proto_desc hook_proto_desc[] = { + [NFPROTO_BRIDGE] = HOOK_PROTO_DESC(PROTO_BASE_LL_HDR, &proto_eth), + [NFPROTO_IPV4] = HOOK_PROTO_DESC(PROTO_BASE_NETWORK_HDR, &proto_ip), + [NFPROTO_IPV6] = HOOK_PROTO_DESC(PROTO_BASE_NETWORK_HDR, &proto_ip6), + [NFPROTO_ARP] = HOOK_PROTO_DESC(PROTO_BASE_NETWORK_HDR, &proto_arp), +}; + +/** + * proto_ctx_init - initialize protocol context for a given hook family + * + * @ctx: protocol context + * @family: hook family + */ +void proto_ctx_init(struct proto_ctx *ctx, unsigned int family) +{ + const struct hook_proto_desc *h = &hook_proto_desc[family]; + + memset(ctx, 0, sizeof(*ctx)); + ctx->family = family; + ctx->protocol[h->base].desc = h->desc; +} + +#define HDR_TEMPLATE(__name, __dtype, __type, __member) \ + PROTO_HDR_TEMPLATE(__name, __dtype, \ + offsetof(__type, __member) * 8, \ + field_sizeof(__type, __member) * 8) + +#define HDR_FIELD(__name, __struct, __member) \ + HDR_TEMPLATE(__name, &integer_type, __struct, __member) +#define HDR_BITFIELD(__name, __dtype, __offset, __len) \ + PROTO_HDR_TEMPLATE(__name, __dtype, __offset, __len) +#define HDR_TYPE(__name, __dtype, __struct, __member) \ + HDR_TEMPLATE(__name, __dtype, __struct, __member) + +#define INET_PROTOCOL(__name, __struct, __member) \ + HDR_TYPE(__name, &inet_protocol_type, __struct, __member) +#define INET_SERVICE(__name, __struct, __member) \ + HDR_TYPE(__name, &inet_service_type, __struct, __member) + +/* + * AH + */ + +#define AHHDR_FIELD(__name, __member) \ + HDR_FIELD(__name, struct ip_auth_hdr, __member) + +const struct proto_desc proto_ah = { + .name = "ah", + .base = PROTO_BASE_TRANSPORT_HDR, + .protocol_key = AHHDR_NEXTHDR, + .protocols = { + PROTO_LINK(IPPROTO_ESP, &proto_esp), + PROTO_LINK(IPPROTO_AH, &proto_ah), + PROTO_LINK(IPPROTO_COMP, &proto_comp), + PROTO_LINK(IPPROTO_UDP, &proto_udp), + PROTO_LINK(IPPROTO_UDPLITE, &proto_udplite), + PROTO_LINK(IPPROTO_TCP, &proto_tcp), + PROTO_LINK(IPPROTO_DCCP, &proto_dccp), + PROTO_LINK(IPPROTO_SCTP, &proto_sctp), + }, + .templates = { + [AHHDR_NEXTHDR] = INET_PROTOCOL("nexthdr", struct ip_auth_hdr, nexthdr), + [AHHDR_HDRLENGTH] = AHHDR_FIELD("hdrlength", hdrlen), + [AHHDR_RESERVED] = AHHDR_FIELD("reserved", reserved), + [AHHDR_SPI] = AHHDR_FIELD("spi", spi), + [AHHDR_SEQUENCE] = AHHDR_FIELD("sequence", seq_no), + }, +}; + +/* + * ESP + */ + +#define ESPHDR_FIELD(__name, __member) \ + HDR_FIELD(__name, struct ip_esp_hdr, __member) + +const struct proto_desc proto_esp = { + .name = "esp", + .base = PROTO_BASE_TRANSPORT_HDR, + .templates = { + [ESPHDR_SPI] = ESPHDR_FIELD("spi", spi), + [ESPHDR_SEQUENCE] = ESPHDR_FIELD("sequence", seq_no), + }, +}; + +/* + * IPCOMP + */ + +#define COMPHDR_FIELD(__name, __member) \ + HDR_FIELD(__name, struct ip_comp_hdr, __member) + +const struct proto_desc proto_comp = { + .name = "comp", + .base = PROTO_BASE_TRANSPORT_HDR, + .protocol_key = COMPHDR_NEXTHDR, + .protocols = { + PROTO_LINK(IPPROTO_ESP, &proto_esp), + PROTO_LINK(IPPROTO_AH, &proto_ah), + PROTO_LINK(IPPROTO_COMP, &proto_comp), + PROTO_LINK(IPPROTO_UDP, &proto_udp), + PROTO_LINK(IPPROTO_UDPLITE, &proto_udplite), + PROTO_LINK(IPPROTO_TCP, &proto_tcp), + PROTO_LINK(IPPROTO_DCCP, &proto_dccp), + PROTO_LINK(IPPROTO_SCTP, &proto_sctp), + }, + .templates = { + [COMPHDR_NEXTHDR] = INET_PROTOCOL("nexthdr", struct ip_comp_hdr, nexthdr), + [COMPHDR_FLAGS] = COMPHDR_FIELD("flags", flags), + [COMPHDR_CPI] = COMPHDR_FIELD("cpi", cpi), + }, +}; + +/* + * ICMP + */ + +#include <netinet/ip_icmp.h> + +static const struct symbol_table icmp_type_tbl = { + .symbols = { + SYMBOL("echo-reply", ICMP_ECHOREPLY), + SYMBOL("destination-unreachable", ICMP_DEST_UNREACH), + SYMBOL("source-quench", ICMP_SOURCE_QUENCH), + SYMBOL("redirect", ICMP_REDIRECT), + SYMBOL("echo-request", ICMP_ECHO), + SYMBOL("time-exceeded", ICMP_TIME_EXCEEDED), + SYMBOL("parameter-problem", ICMP_PARAMETERPROB), + SYMBOL("timestamp-request", ICMP_TIMESTAMP), + SYMBOL("timestamp-reply", ICMP_TIMESTAMPREPLY), + SYMBOL("info-request", ICMP_INFO_REQUEST), + SYMBOL("info-reply", ICMP_INFO_REPLY), + SYMBOL("address-mask-request", ICMP_ADDRESS), + SYMBOL("address-mask-reply", ICMP_ADDRESSREPLY), + SYMBOL_LIST_END + }, +}; + +static const struct datatype icmp_type_type = { + .type = TYPE_ICMP_TYPE, + .name = "icmp_type", + .desc = "ICMP type", + .byteorder = BYTEORDER_BIG_ENDIAN, + .size = BITS_PER_BYTE, + .basetype = &integer_type, + .sym_tbl = &icmp_type_tbl, +}; + +#define ICMPHDR_FIELD(__name, __member) \ + HDR_FIELD(__name, struct icmphdr, __member) +#define ICMPHDR_TYPE(__name, __type, __member) \ + HDR_TYPE(__name, __type, struct icmphdr, __member) + +const struct proto_desc proto_icmp = { + .name = "icmp", + .base = PROTO_BASE_TRANSPORT_HDR, + .templates = { + [ICMPHDR_TYPE] = ICMPHDR_TYPE("type", &icmp_type_type, type), + [ICMPHDR_CODE] = ICMPHDR_FIELD("code", code), + [ICMPHDR_CHECKSUM] = ICMPHDR_FIELD("checksum", checksum), + [ICMPHDR_ID] = ICMPHDR_FIELD("id", un.echo.id), + [ICMPHDR_SEQ] = ICMPHDR_FIELD("sequence", un.echo.sequence), + [ICMPHDR_GATEWAY] = ICMPHDR_FIELD("gateway", un.gateway), + [ICMPHDR_MTU] = ICMPHDR_FIELD("mtu", un.frag.mtu), + }, +}; + +/* + * UDP/UDP-Lite + */ + +#include <netinet/udp.h> +#define UDPHDR_FIELD(__name, __member) \ + HDR_FIELD(__name, struct udphdr, __member) + +const struct proto_desc proto_udp = { + .name = "udp", + .base = PROTO_BASE_TRANSPORT_HDR, + .templates = { + [UDPHDR_SPORT] = INET_SERVICE("sport", struct udphdr, source), + [UDPHDR_DPORT] = INET_SERVICE("dport", struct udphdr, dest), + [UDPHDR_LENGTH] = UDPHDR_FIELD("length", len), + [UDPHDR_CHECKSUM] = UDPHDR_FIELD("checksum", check), + }, +}; + +const struct proto_desc proto_udplite = { + .name = "udplite", + .base = PROTO_BASE_TRANSPORT_HDR, + .templates = { + [UDPHDR_SPORT] = INET_SERVICE("sport", struct udphdr, source), + [UDPHDR_DPORT] = INET_SERVICE("dport", struct udphdr, dest), + [UDPHDR_CSUMCOV] = UDPHDR_FIELD("csumcov", len), + [UDPHDR_CHECKSUM] = UDPHDR_FIELD("checksum", check), + }, +}; + +/* + * TCP + */ + +#include <netinet/tcp.h> + +static const struct symbol_table tcp_flag_tbl = { + .symbols = { + SYMBOL("fin", TCP_FLAG_FIN), + SYMBOL("syn", TCP_FLAG_SYN), + SYMBOL("rst", TCP_FLAG_RST), + SYMBOL("psh", TCP_FLAG_PSH), + SYMBOL("ack", TCP_FLAG_ACK), + SYMBOL("urg", TCP_FLAG_URG), + SYMBOL("ecn", TCP_FLAG_ECN), + SYMBOL("cwr", TCP_FLAG_CWR), + SYMBOL_LIST_END + }, +}; + +static const struct datatype tcp_flag_type = { + .type = TYPE_TCP_FLAG, + .name = "tcp_flag", + .desc = "TCP flag", + .byteorder = BYTEORDER_BIG_ENDIAN, + .size = BITS_PER_BYTE, + .basetype = &bitmask_type, + .sym_tbl = &tcp_flag_tbl, +}; + +#define TCPHDR_FIELD(__name, __member) \ + HDR_FIELD(__name, struct tcphdr, __member) + +const struct proto_desc proto_tcp = { + .name = "tcp", + .base = PROTO_BASE_TRANSPORT_HDR, + .templates = { + [TCPHDR_SPORT] = INET_SERVICE("sport", struct tcphdr, source), + [TCPHDR_DPORT] = INET_SERVICE("dport", struct tcphdr, dest), + [TCPHDR_SEQ] = TCPHDR_FIELD("sequence", seq), + [TCPHDR_ACKSEQ] = TCPHDR_FIELD("ackseq", ack_seq), + [TCPHDR_DOFF] = {}, + [TCPHDR_RESERVED] = {}, + [TCPHDR_FLAGS] = HDR_BITFIELD("flags", &tcp_flag_type, + 13 * BITS_PER_BYTE, + BITS_PER_BYTE), + [TCPHDR_WINDOW] = TCPHDR_FIELD("window", window), + [TCPHDR_CHECKSUM] = TCPHDR_FIELD("checksum", check), + [TCPHDR_URGPTR] = TCPHDR_FIELD("urgptr", urg_ptr), + }, +}; + +/* + * DCCP + */ + +static const struct symbol_table dccp_pkttype_tbl = { + .symbols = { + SYMBOL("request", DCCP_PKT_REQUEST), + SYMBOL("response", DCCP_PKT_RESPONSE), + SYMBOL("data", DCCP_PKT_DATA), + SYMBOL("ack", DCCP_PKT_ACK), + SYMBOL("dataack", DCCP_PKT_DATAACK), + SYMBOL("closereq", DCCP_PKT_CLOSEREQ), + SYMBOL("close", DCCP_PKT_CLOSE), + SYMBOL("reset", DCCP_PKT_RESET), + SYMBOL("sync", DCCP_PKT_SYNC), + SYMBOL("syncack", DCCP_PKT_SYNCACK), + SYMBOL_LIST_END + }, +}; + +static const struct datatype dccp_pkttype_type = { + .type = TYPE_DCCP_PKTTYPE, + .name = "dccp_pkttype", + .desc = "DCCP packet type", + .byteorder = BYTEORDER_INVALID, + .size = 4, + .basetype = &integer_type, + .sym_tbl = &dccp_pkttype_tbl, +}; + + +#define DCCPHDR_FIELD(__name, __member) \ + HDR_FIELD(__name, struct dccp_hdr, __member) + +const struct proto_desc proto_dccp = { + .name = "dccp", + .base = PROTO_BASE_TRANSPORT_HDR, + .templates = { + [DCCPHDR_SPORT] = INET_SERVICE("sport", struct dccp_hdr, dccph_sport), + [DCCPHDR_DPORT] = INET_SERVICE("dport", struct dccp_hdr, dccph_dport), + [DCCPHDR_TYPE] = HDR_BITFIELD("type", &dccp_pkttype_type, 67, 4), + }, +}; + +/* + * SCTP + */ + +#define SCTPHDR_FIELD(__name, __member) \ + HDR_FIELD(__name, struct sctphdr, __member) + +const struct proto_desc proto_sctp = { + .name = "sctp", + .base = PROTO_BASE_TRANSPORT_HDR, + .templates = { + [SCTPHDR_SPORT] = INET_SERVICE("sport", struct sctphdr, source), + [SCTPHDR_DPORT] = INET_SERVICE("dport", struct sctphdr, dest), + [SCTPHDR_VTAG] = SCTPHDR_FIELD("vtag", vtag), + [SCTPHDR_CHECKSUM] = SCTPHDR_FIELD("checksum", checksum), + }, +}; + +/* + * IPv4 + */ + +#include <netinet/ip.h> +#define IPHDR_FIELD(__name, __member) \ + HDR_FIELD(__name, struct iphdr, __member) +#define IPHDR_ADDR(__name, __member) \ + HDR_TYPE(__name, &ipaddr_type, struct iphdr, __member) + +const struct proto_desc proto_ip = { + .name = "ip", + .base = PROTO_BASE_NETWORK_HDR, + .protocol_key = IPHDR_PROTOCOL, + .protocols = { + PROTO_LINK(IPPROTO_ICMP, &proto_icmp), + PROTO_LINK(IPPROTO_ESP, &proto_esp), + PROTO_LINK(IPPROTO_AH, &proto_ah), + PROTO_LINK(IPPROTO_COMP, &proto_comp), + PROTO_LINK(IPPROTO_UDP, &proto_udp), + PROTO_LINK(IPPROTO_UDPLITE, &proto_udplite), + PROTO_LINK(IPPROTO_TCP, &proto_tcp), + PROTO_LINK(IPPROTO_DCCP, &proto_dccp), + PROTO_LINK(IPPROTO_SCTP, &proto_sctp), + }, + .templates = { + [IPHDR_VERSION] = HDR_BITFIELD("version", &integer_type, 0, 4), + [IPHDR_HDRLENGTH] = HDR_BITFIELD("hdrlength", &integer_type, 4, 4), + [IPHDR_TOS] = IPHDR_FIELD("tos", tos), + [IPHDR_LENGTH] = IPHDR_FIELD("length", tot_len), + [IPHDR_ID] = IPHDR_FIELD("id", id), + [IPHDR_FRAG_OFF] = IPHDR_FIELD("frag-off", frag_off), + [IPHDR_TTL] = IPHDR_FIELD("ttl", ttl), + [IPHDR_PROTOCOL] = INET_PROTOCOL("protocol", struct iphdr, protocol), + [IPHDR_CHECKSUM] = IPHDR_FIELD("checksum", check), + [IPHDR_SADDR] = IPHDR_ADDR("saddr", saddr), + [IPHDR_DADDR] = IPHDR_ADDR("daddr", daddr), + }, +}; + +/* + * ICMPv6 + */ + +#include <netinet/icmp6.h> + +static const struct symbol_table icmp6_type_tbl = { + .symbols = { + SYMBOL("destination-unreachable", ICMP6_DST_UNREACH), + SYMBOL("packet-too-big", ICMP6_PACKET_TOO_BIG), + SYMBOL("time-exceeded", ICMP6_TIME_EXCEEDED), + SYMBOL("param-problem", ICMP6_PARAM_PROB), + SYMBOL("echo-request", ICMP6_ECHO_REQUEST), + SYMBOL("echo-reply", ICMP6_ECHO_REPLY), + SYMBOL("mld-listener-query", MLD_LISTENER_QUERY), + SYMBOL("mld-listener-report", MLD_LISTENER_REPORT), + SYMBOL("mld-listener-reduction", MLD_LISTENER_REDUCTION), + SYMBOL("nd-router-solicit", ND_ROUTER_SOLICIT), + SYMBOL("nd-router-advert", ND_ROUTER_ADVERT), + SYMBOL("nd-neighbor-solicit", ND_NEIGHBOR_SOLICIT), + SYMBOL("nd-neighbor-advert", ND_NEIGHBOR_ADVERT), + SYMBOL("nd-redirect", ND_REDIRECT), + SYMBOL("router-renumbering", ICMP6_ROUTER_RENUMBERING), + SYMBOL_LIST_END + }, +}; + +static const struct datatype icmp6_type_type = { + .type = TYPE_ICMP6_TYPE, + .name = "icmpv6_type", + .desc = "ICMPv6 type", + .byteorder = BYTEORDER_BIG_ENDIAN, + .size = BITS_PER_BYTE, + .basetype = &integer_type, + .sym_tbl = &icmp6_type_tbl, +}; + +#define ICMP6HDR_FIELD(__name, __member) \ + HDR_FIELD(__name, struct icmp6_hdr, __member) +#define ICMP6HDR_TYPE(__name, __type, __member) \ + HDR_TYPE(__name, __type, struct icmp6_hdr, __member) + +const struct proto_desc proto_icmp6 = { + .name = "icmpv6", + .base = PROTO_BASE_TRANSPORT_HDR, + .templates = { + [ICMP6HDR_TYPE] = ICMP6HDR_TYPE("type", &icmp6_type_type, icmp6_type), + [ICMP6HDR_CODE] = ICMP6HDR_FIELD("code", icmp6_code), + [ICMP6HDR_CHECKSUM] = ICMP6HDR_FIELD("checksum", icmp6_cksum), + [ICMP6HDR_PPTR] = ICMP6HDR_FIELD("parameter-problem", icmp6_pptr), + [ICMP6HDR_MTU] = ICMP6HDR_FIELD("packet-too-big", icmp6_mtu), + [ICMP6HDR_ID] = ICMP6HDR_FIELD("id", icmp6_id), + [ICMP6HDR_SEQ] = ICMP6HDR_FIELD("sequence", icmp6_seq), + [ICMP6HDR_MAXDELAY] = ICMP6HDR_FIELD("max-delay", icmp6_maxdelay), + }, +}; + +/* + * IPv6 + */ + +#define IP6HDR_FIELD(__name, __member) \ + HDR_FIELD(__name, struct ipv6hdr, __member) +#define IP6HDR_ADDR(__name, __member) \ + HDR_TYPE(__name, &ip6addr_type, struct ipv6hdr, __member) +#define IP6HDR_PROTOCOL(__name, __member) \ + HDR_TYPE(__name, &inet_service_type, struct ipv6hdr, __member) + +const struct proto_desc proto_ip6 = { + .name = "ip6", + .base = PROTO_BASE_NETWORK_HDR, + .protocol_key = IP6HDR_NEXTHDR, + .protocols = { + PROTO_LINK(IPPROTO_ESP, &proto_esp), + PROTO_LINK(IPPROTO_AH, &proto_ah), + PROTO_LINK(IPPROTO_COMP, &proto_comp), + PROTO_LINK(IPPROTO_UDP, &proto_udp), + PROTO_LINK(IPPROTO_UDPLITE, &proto_udplite), + PROTO_LINK(IPPROTO_TCP, &proto_tcp), + PROTO_LINK(IPPROTO_DCCP, &proto_dccp), + PROTO_LINK(IPPROTO_SCTP, &proto_sctp), + PROTO_LINK(IPPROTO_ICMPV6, &proto_icmp6), + }, + .templates = { + [IP6HDR_VERSION] = HDR_BITFIELD("version", &integer_type, 0, 4), + [IP6HDR_PRIORITY] = HDR_BITFIELD("priority", &integer_type, 4, 4), + [IP6HDR_FLOWLABEL] = IP6HDR_FIELD("flowlabel", flow_lbl), + [IP6HDR_LENGTH] = IP6HDR_FIELD("length", payload_len), + [IP6HDR_NEXTHDR] = INET_PROTOCOL("nexthdr", struct ipv6hdr, nexthdr), + [IP6HDR_HOPLIMIT] = IP6HDR_FIELD("hoplimit", hop_limit), + [IP6HDR_SADDR] = IP6HDR_ADDR("saddr", saddr), + [IP6HDR_DADDR] = IP6HDR_ADDR("daddr", daddr), + }, +}; + +/* + * ARP + */ + +#include <net/if_arp.h> + +static const struct symbol_table arpop_tbl = { + .symbols = { + SYMBOL("request", ARPOP_REQUEST), + SYMBOL("reply", ARPOP_REPLY), + SYMBOL("rrequest", ARPOP_RREQUEST), + SYMBOL("rreply", ARPOP_REPLY), + SYMBOL("inrequest", ARPOP_InREQUEST), + SYMBOL("inreply", ARPOP_InREPLY), + SYMBOL("nak", ARPOP_NAK), + SYMBOL_LIST_END + }, +}; + +static const struct datatype arpop_type = { + .type = TYPE_ARPOP, + .name = "arp_op", + .desc = "ARP operation", + .byteorder = BYTEORDER_BIG_ENDIAN, + .size = 2 * BITS_PER_BYTE, + .basetype = &integer_type, + .sym_tbl = &arpop_tbl, +}; + +#define ARPHDR_TYPE(__name, __type, __member) \ + HDR_TYPE(__name, __type, struct arphdr, __member) +#define ARPHDR_FIELD(__name, __member) \ + HDR_FIELD(__name, struct arphdr, __member) + +const struct proto_desc proto_arp = { + .name = "arp", + .base = PROTO_BASE_NETWORK_HDR, + .templates = { + [ARPHDR_HRD] = ARPHDR_FIELD("htype", ar_hrd), + [ARPHDR_PRO] = ARPHDR_TYPE("ptype", ðertype_type, ar_pro), + [ARPHDR_HLN] = ARPHDR_FIELD("hlen", ar_hln), + [ARPHDR_PLN] = ARPHDR_FIELD("plen", ar_pln), + [ARPHDR_OP] = ARPHDR_TYPE("operation", &arpop_type, ar_op), + }, +}; + +/* + * VLAN + */ + +#include <net/ethernet.h> + +#define VLANHDR_BITFIELD(__name, __offset, __len) \ + HDR_BITFIELD(__name, &integer_type, __offset, __len) +#define VLANHDR_TYPE(__name, __type, __member) \ + HDR_TYPE(__name, __type, struct vlan_hdr, __member) + +const struct proto_desc proto_vlan = { + .name = "vlan", + .base = PROTO_BASE_LL_HDR, + .protocol_key = VLANHDR_TYPE, + .protocols = { + PROTO_LINK(ETH_P_IP, &proto_ip), + PROTO_LINK(ETH_P_ARP, &proto_arp), + PROTO_LINK(ETH_P_IPV6, &proto_ip6), + PROTO_LINK(ETH_P_8021Q, &proto_vlan), + + }, + .templates = { + [VLANHDR_VID] = VLANHDR_BITFIELD("id", 0, 12), + [VLANHDR_CFI] = VLANHDR_BITFIELD("cfi", 12, 1), + [VLANHDR_PCP] = VLANHDR_BITFIELD("pcp", 13, 3), + [VLANHDR_TYPE] = VLANHDR_TYPE("type", ðertype_type, vlan_type), + }, +}; + +/* + * Ethernet + */ + +const struct datatype etheraddr_type = { + .type = TYPE_ETHERADDR, + .name = "etheraddr", + .desc = "Ethernet address", + .byteorder = BYTEORDER_HOST_ENDIAN, + .size = ETH_ALEN * BITS_PER_BYTE, + .basetype = &lladdr_type, +}; + +static const struct symbol_table ethertype_tbl = { + .symbols = { + SYMBOL("ip", ETH_P_IP), + SYMBOL("arp", ETH_P_ARP), + SYMBOL("ipv6", ETH_P_IPV6), + SYMBOL("vlan", ETH_P_8021Q), + SYMBOL_LIST_END + }, +}; + +static struct error_record *ethertype_parse(const struct expr *sym, + struct expr **res) +{ + struct error_record *erec; + + erec = sym->dtype->basetype->parse(sym, res); + if (erec != NULL) + return erec; + if (*res) + return NULL; + return symbolic_constant_parse(sym, ðertype_tbl, res); +} + +static void ethertype_print(const struct expr *expr) +{ + return symbolic_constant_print(ðertype_tbl, expr); +} + +const struct datatype ethertype_type = { + .type = TYPE_ETHERTYPE, + .name = "ethertype", + .desc = "Ethernet protocol", + .byteorder = BYTEORDER_BIG_ENDIAN, + .size = 2 * BITS_PER_BYTE, + .basetype = &integer_type, + .basefmt = "0x%.4Zx", + .print = ethertype_print, + .parse = ethertype_parse, +}; + +#define ETHHDR_TEMPLATE(__name, __dtype, __member) \ + HDR_TEMPLATE(__name, __dtype, struct ether_header, __member) +#define ETHHDR_TYPE(__name, __member) \ + ETHHDR_TEMPLATE(__name, ðertype_type, __member) +#define ETHHDR_ADDR(__name, __member) \ + ETHHDR_TEMPLATE(__name, ðeraddr_type, __member) + +const struct proto_desc proto_eth = { + .name = "eth", + .base = PROTO_BASE_LL_HDR, + .protocol_key = ETHHDR_TYPE, + .protocols = { + PROTO_LINK(ETH_P_IP, &proto_ip), + PROTO_LINK(ETH_P_ARP, &proto_arp), + PROTO_LINK(ETH_P_IPV6, &proto_ip6), + PROTO_LINK(ETH_P_8021Q, &proto_vlan), + }, + .templates = { + [ETHHDR_DADDR] = ETHHDR_ADDR("daddr", ether_dhost), + [ETHHDR_SADDR] = ETHHDR_ADDR("saddr", ether_shost), + [ETHHDR_TYPE] = ETHHDR_TYPE("type", ether_type), + }, +}; + +static void __init proto_init(void) +{ + datatype_register(&icmp_type_type); + datatype_register(&tcp_flag_type); + datatype_register(&dccp_pkttype_type); + datatype_register(&arpop_type); + datatype_register(ðertype_type); + datatype_register(&icmp6_type_type); +} |