summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/ct.h1
-rw-r--r--include/datatype.h3
-rw-r--r--include/expression.h18
-rw-r--r--include/exthdr.h6
-rw-r--r--include/linux/netfilter.h22
-rw-r--r--include/linux/netfilter/nf_tables.h130
-rw-r--r--include/nftables.h1
-rw-r--r--include/payload.h288
-rw-r--r--include/proto.h304
-rw-r--r--include/rule.h2
-rw-r--r--include/statement.h11
-rw-r--r--src/Makefile.in1
-rw-r--r--src/ct.c58
-rw-r--r--src/datatype.c18
-rw-r--r--src/evaluate.c49
-rw-r--r--src/exthdr.c26
-rw-r--r--src/main.c6
-rw-r--r--src/meta.c70
-rw-r--r--src/netlink_delinearize.c95
-rw-r--r--src/netlink_linearize.c24
-rw-r--r--src/parser.y110
-rw-r--r--src/payload.c855
-rw-r--r--src/proto.c814
-rw-r--r--src/rule.c3
-rw-r--r--src/scanner.l12
-rw-r--r--src/statement.c31
26 files changed, 1784 insertions, 1174 deletions
diff --git a/include/ct.h b/include/ct.h
index 67718c84..64366ab7 100644
--- a/include/ct.h
+++ b/include/ct.h
@@ -25,5 +25,6 @@ struct ct_template {
extern struct expr *ct_expr_alloc(const struct location *loc,
enum nft_ct_keys key);
+extern void ct_expr_update_type(struct proto_ctx *ctx, struct expr *expr);
#endif /* NFTABLES_CT_H */
diff --git a/include/datatype.h b/include/datatype.h
index 239d5ea5..9f8b44ae 100644
--- a/include/datatype.h
+++ b/include/datatype.h
@@ -6,6 +6,7 @@
*
* @TYPE_INVALID: uninitialized
* @TYPE_VERDICT: nftables verdict
+ * @TYPE_NFPROTO: netfilter protocol (integer subtype)
* @TYPE_BITMASK: bitmask
* @TYPE_INTEGER: integer
* @TYPE_STRING: string
@@ -37,6 +38,7 @@
enum datatypes {
TYPE_INVALID,
TYPE_VERDICT,
+ TYPE_NFPROTO,
TYPE_BITMASK,
TYPE_INTEGER,
TYPE_STRING,
@@ -168,6 +170,7 @@ extern void rt_symbol_table_free(struct symbol_table *tbl);
extern const struct datatype invalid_type;
extern const struct datatype verdict_type;
+extern const struct datatype nfproto_type;
extern const struct datatype bitmask_type;
extern const struct datatype integer_type;
extern const struct datatype string_type;
diff --git a/include/expression.h b/include/expression.h
index f0eb7993..a9aa328e 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -118,7 +118,9 @@ static inline void expr_set_context(struct expr_ctx *ctx,
* @destroy: destructor, must release inner expressions
* @set_type: function to promote type and byteorder of inner types
* @print: function to print the expression
+ * @pctx_update:update protocol context
*/
+struct proto_ctx;
struct expr_ops {
enum expr_types type;
const char *name;
@@ -128,6 +130,8 @@ struct expr_ops {
const struct datatype *dtype,
enum byteorder byteorder);
void (*print)(const struct expr *expr);
+ void (*pctx_update)(struct proto_ctx *ctx,
+ const struct expr *expr);
};
/**
@@ -135,12 +139,14 @@ struct expr_ops {
*
* @EXPR_F_CONSTANT: constant expression
* @EXPR_F_SINGLETON: singleton (implies primary and constant)
+ * @EXPR_F_PROTOCOL: expressions describes upper layer protocol
* @EXPR_F_INTERVAL_END: set member ends an open interval
*/
enum expr_flags {
EXPR_F_CONSTANT = 0x1,
EXPR_F_SINGLETON = 0x2,
- EXPR_F_INTERVAL_END = 0x4,
+ EXPR_F_PROTOCOL = 0x4,
+ EXPR_F_INTERVAL_END = 0x8,
};
#include <payload.h>
@@ -223,20 +229,20 @@ struct expr {
struct {
/* EXPR_PAYLOAD */
- const struct payload_desc *desc;
- const struct payload_template *tmpl;
- enum payload_bases base;
+ const struct proto_desc *desc;
+ const struct proto_hdr_template *tmpl;
+ enum proto_bases base;
unsigned int offset;
- unsigned int flags;
} payload;
struct {
/* EXPR_EXTHDR */
const struct exthdr_desc *desc;
- const struct payload_template *tmpl;
+ const struct proto_hdr_template *tmpl;
} exthdr;
struct {
/* EXPR_META */
enum nft_meta_keys key;
+ enum proto_bases base;
} meta;
struct {
/* EXPR_CT */
diff --git a/include/exthdr.h b/include/exthdr.h
index 62e69bd2..87c42857 100644
--- a/include/exthdr.h
+++ b/include/exthdr.h
@@ -1,17 +1,19 @@
#ifndef NFTABLES_EXTHDR_H
#define NFTABLES_EXTHDR_H
+#include <proto.h>
+
/**
* struct exthdr_desc - extension header description
*
* @name: extension header name
* @type: extension header protocol value
- * @templates: header templates
+ * @templates: header field templates
*/
struct exthdr_desc {
const char *name;
uint8_t type;
- struct payload_template templates[10];
+ struct proto_hdr_template templates[10];
};
extern struct expr *exthdr_expr_alloc(const struct location *loc,
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 2eb00b6c..be0bc182 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -3,6 +3,8 @@
#include <linux/types.h>
+#include <linux/sysctl.h>
+
/* Responses from hook functions. */
#define NF_DROP 0
@@ -14,14 +16,20 @@
#define NF_MAX_VERDICT NF_STOP
/* we overload the higher bits for encoding auxiliary data such as the queue
- * number. Not nice, but better than additional function arguments. */
-#define NF_VERDICT_MASK 0x0000ffff
-#define NF_VERDICT_BITS 16
+ * number or errno values. Not nice, but better than additional function
+ * arguments. */
+#define NF_VERDICT_MASK 0x000000ff
+
+/* extra verdict flags have mask 0x0000ff00 */
+#define NF_VERDICT_FLAG_QUEUE_BYPASS 0x00008000
+/* queue number (NF_QUEUE) or errno (NF_DROP) */
#define NF_VERDICT_QMASK 0xffff0000
#define NF_VERDICT_QBITS 16
-#define NF_QUEUE_NR(x) ((((x) << NF_VERDICT_BITS) & NF_VERDICT_QMASK) | NF_QUEUE)
+#define NF_QUEUE_NR(x) ((((x) << 16) & NF_VERDICT_QMASK) | NF_QUEUE)
+
+#define NF_DROP_ERR(x) (((-x) << 16) | NF_DROP)
/* only for userspace compatibility */
/* Generic cache responses from hook functions.
@@ -29,6 +37,9 @@
#define NFC_UNKNOWN 0x4000
#define NFC_ALTERED 0x8000
+/* NF_VERDICT_BITS should be 8 now, but userspace might break if this changes */
+#define NF_VERDICT_BITS 16
+
enum nf_inet_hooks {
NF_INET_PRE_ROUTING,
NF_INET_LOCAL_IN,
@@ -40,6 +51,7 @@ enum nf_inet_hooks {
enum {
NFPROTO_UNSPEC = 0,
+ NFPROTO_INET = 1,
NFPROTO_IPV4 = 2,
NFPROTO_ARP = 3,
NFPROTO_BRIDGE = 7,
@@ -56,4 +68,4 @@ union nf_inet_addr {
struct in6_addr in6;
};
-#endif /*__LINUX_NETFILTER_H*/
+#endif /* __LINUX_NETFILTER_H */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index a236cc31..448593c0 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -32,6 +32,25 @@ enum nft_verdicts {
NFT_RETURN = -5,
};
+/**
+ * enum nf_tables_msg_types - nf_tables netlink message types
+ *
+ * @NFT_MSG_NEWTABLE: create a new table (enum nft_table_attributes)
+ * @NFT_MSG_GETTABLE: get a table (enum nft_table_attributes)
+ * @NFT_MSG_DELTABLE: delete a table (enum nft_table_attributes)
+ * @NFT_MSG_NEWCHAIN: create a new chain (enum nft_chain_attributes)
+ * @NFT_MSG_GETCHAIN: get a chain (enum nft_chain_attributes)
+ * @NFT_MSG_DELCHAIN: delete a chain (enum nft_chain_attributes)
+ * @NFT_MSG_NEWRULE: create a new rule (enum nft_rule_attributes)
+ * @NFT_MSG_GETRULE: get a rule (enum nft_rule_attributes)
+ * @NFT_MSG_DELRULE: delete a rule (enum nft_rule_attributes)
+ * @NFT_MSG_NEWSET: create a new set (enum nft_set_attributes)
+ * @NFT_MSG_GETSET: get a set (enum nft_set_attributes)
+ * @NFT_MSG_DELSET: delete a set (enum nft_set_attributes)
+ * @NFT_MSG_NEWSETELEM: create a new set element (enum nft_set_elem_attributes)
+ * @NFT_MSG_GETSETELEM: get a set element (enum nft_set_elem_attributes)
+ * @NFT_MSG_DELSETELEM: delete a set element (enum nft_set_elem_attributes)
+ */
enum nf_tables_msg_types {
NFT_MSG_NEWTABLE,
NFT_MSG_GETTABLE,
@@ -48,8 +67,6 @@ enum nf_tables_msg_types {
NFT_MSG_NEWSETELEM,
NFT_MSG_GETSETELEM,
NFT_MSG_DELSETELEM,
- NFT_MSG_COMMIT,
- NFT_MSG_ABORT,
NFT_MSG_MAX,
};
@@ -92,11 +109,14 @@ enum nft_table_flags {
* enum nft_table_attributes - nf_tables table netlink attributes
*
* @NFTA_TABLE_NAME: name of the table (NLA_STRING)
+ * @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32)
+ * @NFTA_TABLE_USE: number of chains in this table (NLA_U32)
*/
enum nft_table_attributes {
NFTA_TABLE_UNSPEC,
NFTA_TABLE_NAME,
NFTA_TABLE_FLAGS,
+ NFTA_TABLE_USE,
__NFTA_TABLE_MAX
};
#define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1)
@@ -105,8 +125,13 @@ enum nft_table_attributes {
* enum nft_chain_attributes - nf_tables chain netlink attributes
*
* @NFTA_CHAIN_TABLE: name of the table containing the chain (NLA_STRING)
+ * @NFTA_CHAIN_HANDLE: numeric handle of the chain (NLA_U64)
* @NFTA_CHAIN_NAME: name of the chain (NLA_STRING)
* @NFTA_CHAIN_HOOK: hook specification for basechains (NLA_NESTED: nft_hook_attributes)
+ * @NFTA_CHAIN_POLICY: numeric policy of the chain (NLA_U32)
+ * @NFTA_CHAIN_USE: number of references to this chain (NLA_U32)
+ * @NFTA_CHAIN_TYPE: type name of the string (NLA_NUL_STRING)
+ * @NFTA_CHAIN_COUNTERS: counter specification of the chain (NLA_NESTED: nft_counter_attributes)
*/
enum nft_chain_attributes {
NFTA_CHAIN_UNSPEC,
@@ -122,18 +147,15 @@ enum nft_chain_attributes {
};
#define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1)
-enum {
- NFT_RULE_F_COMMIT = (1 << 0),
- NFT_RULE_F_MASK = NFT_RULE_F_COMMIT,
-};
-
/**
* enum nft_rule_attributes - nf_tables rule netlink attributes
*
* @NFTA_RULE_TABLE: name of the table containing the rule (NLA_STRING)
* @NFTA_RULE_CHAIN: name of the chain containing the rule (NLA_STRING)
- * @NFTA_RULE_HANDLE: numeric handle of the rule (NLA_U16)
+ * @NFTA_RULE_HANDLE: numeric handle of the rule (NLA_U64)
* @NFTA_RULE_EXPRESSIONS: list of expressions (NLA_NESTED: nft_expr_attributes)
+ * @NFTA_RULE_COMPAT: compatibility specifications of the rule (NLA_NESTED: nft_rule_compat_attributes)
+ * @NFTA_RULE_POSITION: numeric handle of the previous rule (NLA_U64)
*/
enum nft_rule_attributes {
NFTA_RULE_UNSPEC,
@@ -141,17 +163,28 @@ enum nft_rule_attributes {
NFTA_RULE_CHAIN,
NFTA_RULE_HANDLE,
NFTA_RULE_EXPRESSIONS,
- NFTA_RULE_FLAGS,
NFTA_RULE_COMPAT,
+ NFTA_RULE_POSITION,
__NFTA_RULE_MAX
};
#define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1)
+/**
+ * enum nft_rule_compat_flags - nf_tables rule compat flags
+ *
+ * @NFT_RULE_COMPAT_F_INV: invert the check result
+ */
enum nft_rule_compat_flags {
NFT_RULE_COMPAT_F_INV = (1 << 1),
NFT_RULE_COMPAT_F_MASK = NFT_RULE_COMPAT_F_INV,
};
+/**
+ * enum nft_rule_compat_attributes - nf_tables rule compat attributes
+ *
+ * @NFTA_RULE_COMPAT_PROTO: numerice value of handled protocol (NLA_U32)
+ * @NFTA_RULE_COMPAT_FLAGS: bitmask of enum nft_rule_compat_flags (NLA_U32)
+ */
enum nft_rule_compat_attributes {
NFTA_RULE_COMPAT_UNSPEC,
NFTA_RULE_COMPAT_PROTO,
@@ -349,11 +382,26 @@ enum nft_bitwise_attributes {
};
#define NFTA_BITWISE_MAX (__NFTA_BITWISE_MAX - 1)
+/**
+ * enum nft_byteorder_ops - nf_tables byteorder operators
+ *
+ * @NFT_BYTEORDER_NTOH: network to host operator
+ * @NFT_BYTEORDER_HTON: host to network opertaor
+ */
enum nft_byteorder_ops {
NFT_BYTEORDER_NTOH,
NFT_BYTEORDER_HTON,
};
+/**
+ * enum nft_byteorder_attributes - nf_tables byteorder expression netlink attributes
+ *
+ * @NFTA_BYTEORDER_SREG: source register (NLA_U32: nft_registers)
+ * @NFTA_BYTEORDER_DREG: destination register (NLA_U32: nft_registers)
+ * @NFTA_BYTEORDER_OP: operator (NLA_U32: enum nft_byteorder_ops)
+ * @NFTA_BYTEORDER_LEN: length of the data (NLA_U32)
+ * @NFTA_BYTEORDER_SIZE: data size in bytes (NLA_U32: 2 or 4)
+ */
enum nft_byteorder_attributes {
NFTA_BYTEORDER_UNSPEC,
NFTA_BYTEORDER_SREG,
@@ -365,6 +413,16 @@ enum nft_byteorder_attributes {
};
#define NFTA_BYTEORDER_MAX (__NFTA_BYTEORDER_MAX - 1)
+/**
+ * enum nft_cmp_ops - nf_tables relational operator
+ *
+ * @NFT_CMP_EQ: equal
+ * @NFT_CMP_NEQ: not equal
+ * @NFT_CMP_LT: less than
+ * @NFT_CMP_LTE: less than or equal to
+ * @NFT_CMP_GT: greater than
+ * @NFT_CMP_GTE: greater than or equal to
+ */
enum nft_cmp_ops {
NFT_CMP_EQ,
NFT_CMP_NEQ,
@@ -390,6 +448,13 @@ enum nft_cmp_attributes {
};
#define NFTA_CMP_MAX (__NFTA_CMP_MAX - 1)
+/**
+ * enum nft_lookup_attributes - nf_tables set lookup expression netlink attributes
+ *
+ * @NFTA_LOOKUP_SET: name of the set where to look for (NLA_STRING)
+ * @NFTA_LOOKUP_SREG: source register of the data to look for (NLA_U32: nft_registers)
+ * @NFTA_LOOKUP_DREG: destination register (NLA_U32: nft_registers)
+ */
enum nft_lookup_attributes {
NFTA_LOOKUP_UNSPEC,
NFTA_LOOKUP_SET,
@@ -430,6 +495,14 @@ enum nft_payload_attributes {
};
#define NFTA_PAYLOAD_MAX (__NFTA_PAYLOAD_MAX - 1)
+/**
+ * enum nft_exthdr_attributes - nf_tables IPv6 extension header expression netlink attributes
+ *
+ * @NFTA_EXTHDR_DREG: destination register (NLA_U32: nft_registers)
+ * @NFTA_EXTHDR_TYPE: extension header type (NLA_U8)
+ * @NFTA_EXTHDR_OFFSET: extension header offset (NLA_U32)
+ * @NFTA_EXTHDR_LEN: extension header length (NLA_U32)
+ */
enum nft_exthdr_attributes {
NFTA_EXTHDR_UNSPEC,
NFTA_EXTHDR_DREG,
@@ -458,6 +531,8 @@ enum nft_exthdr_attributes {
* @NFT_META_NFTRACE: packet nftrace bit
* @NFT_META_RTCLASSID: realm value of packet's route (skb->dst->tclassid)
* @NFT_META_SECMARK: packet secmark (skb->secmark)
+ * @NFT_META_NFPROTO: netfilter protocol
+ * @NFT_META_L4PROTO: layer 4 protocol number
*/
enum nft_meta_keys {
NFT_META_LEN,
@@ -475,6 +550,8 @@ enum nft_meta_keys {
NFT_META_NFTRACE,
NFT_META_RTCLASSID,
NFT_META_SECMARK,
+ NFT_META_NFPROTO,
+ NFT_META_L4PROTO,
};
/**
@@ -482,11 +559,13 @@ enum nft_meta_keys {
*
* @NFTA_META_DREG: destination register (NLA_U32)
* @NFTA_META_KEY: meta data item to load (NLA_U32: nft_meta_keys)
+ * @NFTA_META_SREG: source register (NLA_U32)
*/
enum nft_meta_attributes {
NFTA_META_UNSPEC,
NFTA_META_DREG,
NFTA_META_KEY,
+ NFTA_META_SREG,
__NFTA_META_MAX
};
#define NFTA_META_MAX (__NFTA_META_MAX - 1)
@@ -544,12 +623,12 @@ enum nft_ct_attributes {
* enum nft_limit_attributes - nf_tables limit expression netlink attributes
*
* @NFTA_LIMIT_RATE: refill rate (NLA_U64)
- * @NFTA_LIMIT_DEPTH: bucket depth (NLA_U64)
+ * @NFTA_LIMIT_UNIT: refill unit (NLA_U64)
*/
enum nft_limit_attributes {
NFTA_LIMIT_UNSPEC,
NFTA_LIMIT_RATE,
- NFTA_LIMIT_DEPTH,
+ NFTA_LIMIT_UNIT,
__NFTA_LIMIT_MAX
};
#define NFTA_LIMIT_MAX (__NFTA_LIMIT_MAX - 1)
@@ -587,6 +666,26 @@ enum nft_log_attributes {
#define NFTA_LOG_MAX (__NFTA_LOG_MAX - 1)
/**
+ * enum nft_queue_attributes - nf_tables queue expression netlink attributes
+ *
+ * @NFTA_QUEUE_NUM: netlink queue to send messages to (NLA_U16)
+ * @NFTA_QUEUE_TOTAL: number of queues to load balance packets on (NLA_U16)
+ * @NFTA_QUEUE_FLAGS: various flags (NLA_U16)
+ */
+enum nft_queue_attributes {
+ NFTA_QUEUE_UNSPEC,
+ NFTA_QUEUE_NUM,
+ NFTA_QUEUE_TOTAL,
+ NFTA_QUEUE_FLAGS,
+ __NFTA_QUEUE_MAX
+};
+#define NFTA_QUEUE_MAX (__NFTA_QUEUE_MAX - 1)
+
+#define NFT_QUEUE_FLAG_BYPASS 0x01 /* for compatibility with v2 */
+#define NFT_QUEUE_FLAG_CPU_FANOUT 0x02 /* use current CPU (no hashing) */
+#define NFT_QUEUE_FLAG_MASK 0x03
+
+/**
* enum nft_reject_types - nf_tables reject expression reject types
*
* @NFT_REJECT_ICMP_UNREACH: reject using ICMP unreachable
@@ -626,10 +725,11 @@ enum nft_nat_types {
* enum nft_nat_attributes - nf_tables nat expression netlink attributes
*
* @NFTA_NAT_TYPE: NAT type (NLA_U32: nft_nat_types)
- * @NFTA_NAT_ADDR_MIN: source register of address range start (NLA_U32: nft_registers)
- * @NFTA_NAT_ADDR_MAX: source register of address range end (NLA_U32: nft_registers)
- * @NFTA_NAT_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
- * @NFTA_NAT_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers)
+ * @NFTA_NAT_FAMILY: NAT family (NLA_U32)
+ * @NFTA_NAT_REG_ADDR_MIN: source register of address range start (NLA_U32: nft_registers)
+ * @NFTA_NAT_REG_ADDR_MAX: source register of address range end (NLA_U32: nft_registers)
+ * @NFTA_NAT_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
+ * @NFTA_NAT_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers)
*/
enum nft_nat_attributes {
NFTA_NAT_UNSPEC,
diff --git a/include/nftables.h b/include/nftables.h
index 12f3c492..801000e1 100644
--- a/include/nftables.h
+++ b/include/nftables.h
@@ -17,6 +17,7 @@ enum debug_level {
DEBUG_PARSER = 0x2,
DEBUG_EVALUATION = 0x4,
DEBUG_NETLINK = 0x8,
+ DEBUG_PROTO_CTX = 0x10,
};
#define INCLUDE_PATHS_MAX 16
diff --git a/include/payload.h b/include/payload.h
index c9cc84f3..d47e5645 100644
--- a/include/payload.h
+++ b/include/payload.h
@@ -2,138 +2,14 @@
#define NFTABLES_PAYLOAD_H
#include <nftables.h>
-
-/**
- * enum payload_bases
- *
- * @PAYLOAD_BASE_INVALID: uninitialised, does not happen
- * @PAYLOAD_BASE_LL_HDR: link layer header
- * @PAYLOAD_BASE_NETWORK_HDR: network layer header
- * @PAYLOAD_BASE_TRANSPORT_HDR: transport layer header
- */
-enum payload_bases {
- PAYLOAD_BASE_INVALID,
- PAYLOAD_BASE_LL_HDR,
- PAYLOAD_BASE_NETWORK_HDR,
- PAYLOAD_BASE_TRANSPORT_HDR,
- __PAYLOAD_BASE_MAX
-};
-#define PAYLOAD_BASE_MAX (__PAYLOAD_BASE_MAX - 1)
-
-/**
- * enum payload_expr_flags
- *
- * @PAYLOAD_PROTOCOL_EXPR: payload expression contains upper layer protocol
- */
-enum payload_expr_flags {
- PAYLOAD_PROTOCOL_EXPR = 0x1,
-};
-
-/**
- * struct payload_template - template for a payload header expression
- *
- * @token: parser token describing the header field
- * @dtype: data type of the expression
- * @offset: offset from base
- * @len: length of header field
- */
-struct payload_template {
- const char *token;
- const struct datatype *dtype;
- uint16_t offset;
- uint16_t len;
-};
-
-#define PAYLOAD_TEMPLATE(__token, __dtype, __offset, __len) \
- { \
- .token = (__token), \
- .dtype = (__dtype), \
- .offset = (__offset), \
- .len = (__len), \
- }
-
-#define PAYLOAD_PROTO_MAX 16
-#define PAYLOAD_TEMPLATE_MAX 20
-
-/**
- * struct payload_desc - payload protocol description
- *
- * @name: protocol name
- * @base: header base
- * @protocol_key: key of template containing upper layer protocol description
- * @protocols: link to upper layer protocol description indexed by protocol value
- * @templates: header templates
- */
-struct payload_desc {
- const char *name;
- enum payload_bases base;
- unsigned int protocol_key;
- struct {
- unsigned int num;
- const struct payload_desc *desc;
- } protocols[PAYLOAD_PROTO_MAX];
- struct payload_template templates[PAYLOAD_TEMPLATE_MAX];
-};
-
-#define PAYLOAD_PROTO(__num, __desc) { .num = (__num), .desc = (__desc), }
-
-/**
- * struct payload_hook_desc - description of constraints imposed by hook family
- *
- * @base: protocol base of packets
- * @desc: protocol description of packets
- */
-struct payload_hook_desc {
- enum payload_bases base;
- const struct payload_desc *desc;
-};
-
-#define PAYLOAD_HOOK(__base, __desc) { .base = (__base), .desc = (__desc), }
-
-/**
- * struct dev_payload_desc - description of device LL protocol
- *
- * @desc: protocol description
- * @type: arphrd value
- */
-struct dev_payload_desc {
- const struct payload_desc *desc;
- uint16_t type;
-};
-
-#define DEV_PAYLOAD_DESC(__type, __desc) { .type = (__type), .desc = (__desc), }
-
-/**
- * struct payload_ctx - payload expression protocol context
- *
- * @family: hook family
- * @location: location of expression defining the context
- * @desc: payload description for this layer
- *
- * The location of the context is the location of the relational expression
- * defining it, either directly through a protocol match or indirectly
- * through a dependency.
- */
-struct payload_ctx {
- unsigned int family;
- struct {
- struct location location;
- const struct payload_desc *desc;
- } protocol[PAYLOAD_BASE_MAX + 1];
-};
+#include <proto.h>
extern struct expr *payload_expr_alloc(const struct location *loc,
- const struct payload_desc *desc,
+ const struct proto_desc *desc,
unsigned int type);
-extern void payload_init_raw(struct expr *expr, enum payload_bases base,
+extern void payload_init_raw(struct expr *expr, enum proto_bases base,
unsigned int offset, unsigned int len);
-extern void payload_ctx_init(struct payload_ctx *ctx, unsigned int family);
-extern void payload_ctx_update_meta(struct payload_ctx *ctx,
- const struct expr *expr);
-extern void payload_ctx_update(struct payload_ctx *ctx,
- const struct expr *expr);
-
struct eval_ctx;
extern int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
struct expr **res);
@@ -143,162 +19,8 @@ extern struct expr *payload_expr_join(const struct expr *e1,
const struct expr *e2);
extern void payload_expr_expand(struct list_head *list, struct expr *expr,
- const struct payload_ctx *ctx);
+ const struct proto_ctx *ctx);
extern void payload_expr_complete(struct expr *expr,
- const struct payload_ctx *ctx);
-
-enum eth_hdr_fields {
- ETHHDR_INVALID,
- ETHHDR_DADDR,
- ETHHDR_SADDR,
- ETHHDR_TYPE,
-};
-
-enum vlan_hdr_fields {
- VLANHDR_INVALID,
- VLANHDR_VID,
- VLANHDR_CFI,
- VLANHDR_PCP,
- VLANHDR_TYPE,
-};
-
-enum arp_hdr_fields {
- ARPHDR_INVALID,
- ARPHDR_HRD,
- ARPHDR_PRO,
- ARPHDR_HLN,
- ARPHDR_PLN,
- ARPHDR_OP,
-};
-
-enum ip_hdr_fields {
- IPHDR_INVALID,
- IPHDR_VERSION,
- IPHDR_HDRLENGTH,
- IPHDR_TOS,
- IPHDR_LENGTH,
- IPHDR_ID,
- IPHDR_FRAG_OFF,
- IPHDR_TTL,
- IPHDR_PROTOCOL,
- IPHDR_CHECKSUM,
- IPHDR_SADDR,
- IPHDR_DADDR,
-};
-
-enum icmp_hdr_fields {
- ICMPHDR_INVALID,
- ICMPHDR_TYPE,
- ICMPHDR_CODE,
- ICMPHDR_CHECKSUM,
- ICMPHDR_ID,
- ICMPHDR_SEQ,
- ICMPHDR_GATEWAY,
- ICMPHDR_MTU,
-};
-
-enum icmp6_hdr_fields {
- ICMP6HDR_INVALID,
- ICMP6HDR_TYPE,
- ICMP6HDR_CODE,
- ICMP6HDR_CHECKSUM,
- ICMP6HDR_PPTR,
- ICMP6HDR_MTU,
- ICMP6HDR_ID,
- ICMP6HDR_SEQ,
- ICMP6HDR_MAXDELAY,
-};
-
-enum ip6_hdr_fields {
- IP6HDR_INVALID,
- IP6HDR_VERSION,
- IP6HDR_PRIORITY,
- IP6HDR_FLOWLABEL,
- IP6HDR_LENGTH,
- IP6HDR_NEXTHDR,
- IP6HDR_HOPLIMIT,
- IP6HDR_SADDR,
- IP6HDR_DADDR,
- IP6HDR_PROTOCOL,
-};
-
-enum ah_hdr_fields {
- AHHDR_INVALID,
- AHHDR_NEXTHDR,
- AHHDR_HDRLENGTH,
- AHHDR_RESERVED,
- AHHDR_SPI,
- AHHDR_SEQUENCE,
-};
-
-enum esp_hdr_fields {
- ESPHDR_INVALID,
- ESPHDR_SPI,
- ESPHDR_SEQUENCE,
-};
-
-enum comp_hdr_fields {
- COMPHDR_INVALID,
- COMPHDR_NEXTHDR,
- COMPHDR_FLAGS,
- COMPHDR_CPI,
-};
-
-enum udp_hdr_fields {
- UDPHDR_INVALID,
- UDPHDR_SPORT,
- UDPHDR_DPORT,
- UDPHDR_LENGTH,
- UDPHDR_CSUMCOV = UDPHDR_LENGTH,
- UDPHDR_CHECKSUM,
-};
-
-enum tcp_hdr_fields {
- TCPHDR_INVALID,
- TCPHDR_SPORT,
- TCPHDR_DPORT,
- TCPHDR_SEQ,
- TCPHDR_ACKSEQ,
- TCPHDR_DOFF,
- TCPHDR_RESERVED,
- TCPHDR_FLAGS,
- TCPHDR_WINDOW,
- TCPHDR_CHECKSUM,
- TCPHDR_URGPTR,
-};
-
-enum dccp_hdr_fields {
- DCCPHDR_INVALID,
- DCCPHDR_SPORT,
- DCCPHDR_DPORT,
- DCCPHDR_TYPE,
-};
-
-enum sctp_hdr_fields {
- SCTPHDR_INVALID,
- SCTPHDR_SPORT,
- SCTPHDR_DPORT,
- SCTPHDR_VTAG,
- SCTPHDR_CHECKSUM,
-};
-
-extern const struct payload_desc payload_icmp;
-extern const struct payload_desc payload_ah;
-extern const struct payload_desc payload_esp;
-extern const struct payload_desc payload_comp;
-extern const struct payload_desc payload_udp;
-extern const struct payload_desc payload_udplite;
-extern const struct payload_desc payload_tcp;
-extern const struct payload_desc payload_dccp;
-extern const struct payload_desc payload_sctp;
-extern const struct payload_desc payload_icmp6;
-
-extern const struct payload_desc payload_ip;
-extern const struct payload_desc payload_ip6;
-
-extern const struct payload_desc payload_arp;
-
-extern const struct payload_desc payload_vlan;
-extern const struct payload_desc payload_eth;
+ const struct proto_ctx *ctx);
#endif /* NFTABLES_PAYLOAD_H */
diff --git a/include/proto.h b/include/proto.h
new file mode 100644
index 00000000..bd3701e3
--- /dev/null
+++ b/include/proto.h
@@ -0,0 +1,304 @@
+#ifndef NFTABLES_PROTO_H
+#define NFTABLES_PROTO_H
+
+#include <nftables.h>
+#include <linux/netfilter/nf_tables.h>
+
+/**
+ * enum proto_bases - protocol bases
+ *
+ * @PROTO_BASE_INVALID: uninitialised, does not happen
+ * @PROTO_BASE_LL_HDR: link layer header
+ * @PROTO_BASE_NETWORK_HDR: network layer header
+ * @PROTO_BASE_TRANSPORT_HDR: transport layer header
+ */
+enum proto_bases {
+ PROTO_BASE_INVALID,
+ PROTO_BASE_LL_HDR,
+ PROTO_BASE_NETWORK_HDR,
+ PROTO_BASE_TRANSPORT_HDR,
+ __PROTO_BASE_MAX
+};
+#define PROTO_BASE_MAX (__PROTO_BASE_MAX - 1)
+
+extern const char *proto_base_names[];
+extern const char *proto_base_tokens[];
+
+/**
+ * struct proto_hdr_template - protocol header field description
+ *
+ * @token: parser token describing the header field
+ * @dtype: data type of the header field
+ * @offset: offset of the header field from base
+ * @len: length of header field
+ * @meta_key: special case: meta expression key
+ */
+struct proto_hdr_template {
+ const char *token;
+ const struct datatype *dtype;
+ uint16_t offset;
+ uint16_t len;
+ enum nft_meta_keys meta_key;
+};
+
+#define PROTO_HDR_TEMPLATE(__token, __dtype, __offset, __len) \
+ { \
+ .token = (__token), \
+ .dtype = (__dtype), \
+ .offset = (__offset), \
+ .len = (__len), \
+ }
+
+#define PROTO_META_TEMPLATE(__token, __dtype, __key, __len) \
+ { \
+ .token = (__token), \
+ .dtype = (__dtype), \
+ .meta_key = (__key), \
+ .len = (__len), \
+ }
+
+#define PROTO_UPPER_MAX 16
+#define PROTO_HDRS_MAX 20
+
+/**
+ * struct proto_desc - protocol header description
+ *
+ * @name: protocol name
+ * @base: header base
+ * @protocol_key: key of template containing upper layer protocol description
+ * @protocols: link to upper layer protocol descriptions indexed by protocol value
+ * @templates: header templates
+ */
+struct proto_desc {
+ const char *name;
+ enum proto_bases base;
+ unsigned int protocol_key;
+ struct {
+ unsigned int num;
+ const struct proto_desc *desc;
+ } protocols[PROTO_UPPER_MAX];
+ struct proto_hdr_template templates[PROTO_HDRS_MAX];
+};
+
+#define PROTO_LINK(__num, __desc) { .num = (__num), .desc = (__desc), }
+
+/**
+ * struct hook_proto_desc - description of protocol constraints imposed by hook family
+ *
+ * @base: protocol base of packets
+ * @desc: protocol description of packets
+ */
+struct hook_proto_desc {
+ enum proto_bases base;
+ const struct proto_desc *desc;
+};
+
+#define HOOK_PROTO_DESC(__base, __desc) { .base = (__base), .desc = (__desc), }
+
+extern const struct hook_proto_desc hook_proto_desc[];
+
+/**
+ * struct dev_proto_desc - description of device LL protocol
+ *
+ * @desc: protocol description
+ * @type: arphrd value
+ */
+struct dev_proto_desc {
+ const struct proto_desc *desc;
+ uint16_t type;
+};
+
+#define DEV_PROTO_DESC(__type, __desc) { .type = (__type), .desc = (__desc), }
+
+extern int proto_dev_type(const struct proto_desc *desc, uint16_t *res);
+extern const struct proto_desc *proto_dev_desc(uint16_t type);
+
+/**
+ * struct proto_ctx - protocol context
+ *
+ * @family: hook family
+ * @location: location of the relational expression defining the context
+ * @desc: protocol description for this layer
+ *
+ * The location of the context is the location of the relational expression
+ * defining it, either directly through a protocol match or indirectly
+ * through a dependency.
+ */
+struct proto_ctx {
+ unsigned int family;
+ struct {
+ struct location location;
+ const struct proto_desc *desc;
+ } protocol[PROTO_BASE_MAX + 1];
+};
+
+extern void proto_ctx_init(struct proto_ctx *ctx, unsigned int family);
+extern void proto_ctx_update(struct proto_ctx *ctx, enum proto_bases base,
+ const struct location *loc,
+ const struct proto_desc *desc);
+extern const struct proto_desc *proto_find_upper(const struct proto_desc *base,
+ unsigned int num);
+extern int proto_find_num(const struct proto_desc *base,
+ const struct proto_desc *desc);
+
+enum eth_hdr_fields {
+ ETHHDR_INVALID,
+ ETHHDR_DADDR,
+ ETHHDR_SADDR,
+ ETHHDR_TYPE,
+};
+
+enum vlan_hdr_fields {
+ VLANHDR_INVALID,
+ VLANHDR_VID,
+ VLANHDR_CFI,
+ VLANHDR_PCP,
+ VLANHDR_TYPE,
+};
+
+enum arp_hdr_fields {
+ ARPHDR_INVALID,
+ ARPHDR_HRD,
+ ARPHDR_PRO,
+ ARPHDR_HLN,
+ ARPHDR_PLN,
+ ARPHDR_OP,
+};
+
+enum ip_hdr_fields {
+ IPHDR_INVALID,
+ IPHDR_VERSION,
+ IPHDR_HDRLENGTH,
+ IPHDR_TOS,
+ IPHDR_LENGTH,
+ IPHDR_ID,
+ IPHDR_FRAG_OFF,
+ IPHDR_TTL,
+ IPHDR_PROTOCOL,
+ IPHDR_CHECKSUM,
+ IPHDR_SADDR,
+ IPHDR_DADDR,
+};
+
+enum icmp_hdr_fields {
+ ICMPHDR_INVALID,
+ ICMPHDR_TYPE,
+ ICMPHDR_CODE,
+ ICMPHDR_CHECKSUM,
+ ICMPHDR_ID,
+ ICMPHDR_SEQ,
+ ICMPHDR_GATEWAY,
+ ICMPHDR_MTU,
+};
+
+enum icmp6_hdr_fields {
+ ICMP6HDR_INVALID,
+ ICMP6HDR_TYPE,
+ ICMP6HDR_CODE,
+ ICMP6HDR_CHECKSUM,
+ ICMP6HDR_PPTR,
+ ICMP6HDR_MTU,
+ ICMP6HDR_ID,
+ ICMP6HDR_SEQ,
+ ICMP6HDR_MAXDELAY,
+};
+
+enum ip6_hdr_fields {
+ IP6HDR_INVALID,
+ IP6HDR_VERSION,
+ IP6HDR_PRIORITY,
+ IP6HDR_FLOWLABEL,
+ IP6HDR_LENGTH,
+ IP6HDR_NEXTHDR,
+ IP6HDR_HOPLIMIT,
+ IP6HDR_SADDR,
+ IP6HDR_DADDR,
+ IP6HDR_PROTOCOL,
+};
+
+enum ah_hdr_fields {
+ AHHDR_INVALID,
+ AHHDR_NEXTHDR,
+ AHHDR_HDRLENGTH,
+ AHHDR_RESERVED,
+ AHHDR_SPI,
+ AHHDR_SEQUENCE,
+};
+
+enum esp_hdr_fields {
+ ESPHDR_INVALID,
+ ESPHDR_SPI,
+ ESPHDR_SEQUENCE,
+};
+
+enum comp_hdr_fields {
+ COMPHDR_INVALID,
+ COMPHDR_NEXTHDR,
+ COMPHDR_FLAGS,
+ COMPHDR_CPI,
+};
+
+enum udp_hdr_fields {
+ UDPHDR_INVALID,
+ UDPHDR_SPORT,
+ UDPHDR_DPORT,
+ UDPHDR_LENGTH,
+ UDPHDR_CSUMCOV = UDPHDR_LENGTH,
+ UDPHDR_CHECKSUM,
+};
+
+enum tcp_hdr_fields {
+ TCPHDR_INVALID,
+ TCPHDR_SPORT,
+ TCPHDR_DPORT,
+ TCPHDR_SEQ,
+ TCPHDR_ACKSEQ,
+ TCPHDR_DOFF,
+ TCPHDR_RESERVED,
+ TCPHDR_FLAGS,
+ TCPHDR_WINDOW,
+ TCPHDR_CHECKSUM,
+ TCPHDR_URGPTR,
+};
+
+enum dccp_hdr_fields {
+ DCCPHDR_INVALID,
+ DCCPHDR_SPORT,
+ DCCPHDR_DPORT,
+ DCCPHDR_TYPE,
+};
+
+enum sctp_hdr_fields {
+ SCTPHDR_INVALID,
+ SCTPHDR_SPORT,
+ SCTPHDR_DPORT,
+ SCTPHDR_VTAG,
+ SCTPHDR_CHECKSUM,
+};
+
+extern const struct proto_desc proto_icmp;
+extern const struct proto_desc proto_ah;
+extern const struct proto_desc proto_esp;
+extern const struct proto_desc proto_comp;
+extern const struct proto_desc proto_udp;
+extern const struct proto_desc proto_udplite;
+extern const struct proto_desc proto_tcp;
+extern const struct proto_desc proto_dccp;
+extern const struct proto_desc proto_sctp;
+extern const struct proto_desc proto_icmp6;
+
+extern const struct proto_desc proto_ip;
+extern const struct proto_desc proto_ip6;
+
+extern const struct proto_desc proto_inet;
+extern const struct proto_desc proto_inet_service;
+
+extern const struct proto_desc proto_arp;
+
+extern const struct proto_desc proto_vlan;
+extern const struct proto_desc proto_eth;
+
+extern const struct proto_desc proto_unknown;
+extern const struct proto_hdr_template proto_unknown_template;
+
+#endif /* NFTABLES_PROTO_H */
diff --git a/include/rule.h b/include/rule.h
index 6ad8af3b..2a7b7980 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -292,7 +292,7 @@ struct eval_ctx {
struct set *set;
struct stmt *stmt;
struct expr_ctx ectx;
- struct payload_ctx pctx;
+ struct proto_ctx pctx;
};
extern int evaluate(struct eval_ctx *ctx, struct list_head *commands);
diff --git a/include/statement.h b/include/statement.h
index 6ecbb18d..14a66df6 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -59,6 +59,14 @@ struct nat_stmt {
extern struct stmt *nat_stmt_alloc(const struct location *loc);
+struct queue_stmt {
+ uint16_t queuenum;
+ uint16_t queues_total;
+ uint16_t flags;
+};
+
+extern struct stmt *queue_stmt_alloc(const struct location *loc);
+
/**
* enum stmt_types - statement types
*
@@ -71,6 +79,7 @@ extern struct stmt *nat_stmt_alloc(const struct location *loc);
* @STMT_LOG: log statement
* @STMT_REJECT: REJECT statement
* @STMT_NAT: NAT statement
+ * @STMT_QUEUE: QUEUE statement
*/
enum stmt_types {
STMT_INVALID,
@@ -82,6 +91,7 @@ enum stmt_types {
STMT_LOG,
STMT_REJECT,
STMT_NAT,
+ STMT_QUEUE,
};
/**
@@ -127,6 +137,7 @@ struct stmt {
struct limit_stmt limit;
struct reject_stmt reject;
struct nat_stmt nat;
+ struct queue_stmt queue;
};
};
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/ct.c b/src/ct.c
index e5ca593c..b8f76325 100644
--- a/src/ct.c
+++ b/src/ct.c
@@ -23,6 +23,7 @@
#include <expression.h>
#include <datatype.h>
#include <ct.h>
+#include <gmputil.h>
#include <utils.h>
static const struct symbol_table ct_state_tbl = {
@@ -139,11 +140,32 @@ static void ct_expr_clone(struct expr *new, const struct expr *expr)
new->ct.key = expr->ct.key;
}
+static void ct_expr_pctx_update(struct proto_ctx *ctx, const struct expr *expr)
+{
+ const struct expr *left = expr->left, *right = expr->right;
+ const struct proto_desc *base, *desc;
+
+ assert(expr->op == OP_EQ);
+
+ switch (left->ct.key) {
+ case NFT_CT_PROTOCOL:
+ base = ctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
+ desc = proto_find_upper(base, mpz_get_uint32(right->value));
+
+ proto_ctx_update(ctx, PROTO_BASE_TRANSPORT_HDR,
+ &expr->location, desc);
+ break;
+ default:
+ break;
+ }
+}
+
static const struct expr_ops ct_expr_ops = {
.type = EXPR_CT,
.name = "ct",
.print = ct_expr_print,
.clone = ct_expr_clone,
+ .pctx_update = ct_expr_pctx_update,
};
struct expr *ct_expr_alloc(const struct location *loc, enum nft_ct_keys key)
@@ -154,9 +176,45 @@ struct expr *ct_expr_alloc(const struct location *loc, enum nft_ct_keys key)
expr = expr_alloc(loc, &ct_expr_ops, tmpl->dtype,
tmpl->byteorder, tmpl->len);
expr->ct.key = key;
+
+ switch (key) {
+ case NFT_CT_PROTOCOL:
+ expr->flags = EXPR_F_PROTOCOL;
+ break;
+ default:
+ break;
+ }
+
return expr;
}
+void ct_expr_update_type(struct proto_ctx *ctx, struct expr *expr)
+{
+ const struct proto_desc *desc;
+
+ switch (expr->ct.key) {
+ case NFT_CT_SRC:
+ case NFT_CT_DST:
+ desc = ctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
+ if (desc == &proto_ip)
+ expr->dtype = &ipaddr_type;
+ else if (desc == &proto_ip6)
+ expr->dtype = &ip6addr_type;
+
+ expr->len = expr->dtype->size;
+ break;
+ case NFT_CT_PROTO_SRC:
+ case NFT_CT_PROTO_DST:
+ desc = ctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc;
+ if (desc == NULL)
+ break;
+ expr->dtype = &inet_service_type;
+ break;
+ default:
+ break;
+ }
+}
+
static void __init ct_init(void)
{
datatype_register(&ct_state_type);
diff --git a/src/datatype.c b/src/datatype.c
index 86ea80e3..e228f530 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -26,6 +26,7 @@
static const struct datatype *datatypes[TYPE_MAX + 1] = {
[TYPE_INVALID] = &invalid_type,
[TYPE_VERDICT] = &verdict_type,
+ [TYPE_NFPROTO] = &nfproto_type,
[TYPE_BITMASK] = &bitmask_type,
[TYPE_INTEGER] = &integer_type,
[TYPE_STRING] = &string_type,
@@ -204,6 +205,23 @@ const struct datatype verdict_type = {
.print = verdict_type_print,
};
+static const struct symbol_table nfproto_tbl = {
+ .symbols = {
+ SYMBOL("ipv4", NFPROTO_IPV4),
+ SYMBOL("ipv6", NFPROTO_IPV6),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype nfproto_type = {
+ .type = TYPE_NFPROTO,
+ .name = "nfproto",
+ .desc = "netfilter protocol",
+ .size = 1 * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .sym_tbl = &nfproto_tbl,
+};
+
const struct datatype bitmask_type = {
.type = TYPE_BITMASK,
.name = "bitmask",
diff --git a/src/evaluate.c b/src/evaluate.c
index 94fee64b..4ca32943 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;
@@ -290,6 +290,19 @@ static int expr_evaluate_payload(struct eval_ctx *ctx, struct expr **expr)
}
/*
+ * CT expression: update the protocol dependant types bases on the protocol
+ * context.
+ */
+static int expr_evaluate_ct(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct expr *ct = *expr;
+
+ ct_expr_update_type(&ctx->pctx, ct);
+
+ return expr_evaluate_primary(ctx, expr);
+}
+
+/*
* Prefix expression: the argument must be a constant value of integer base
* type; the prefix length must be less than or equal to the type width.
*/
@@ -916,21 +929,17 @@ 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);
- break;
- case EXPR_META:
- payload_ctx_update_meta(&ctx->pctx, rel);
- break;
- case EXPR_CONCAT:
+ if (left->flags & EXPR_F_PROTOCOL &&
+ left->ops->pctx_update)
+ left->ops->pctx_update(&ctx->pctx, rel);
+
+ if (left->ops->type == EXPR_CONCAT)
return 0;
- default:
- break;
- }
+
+ /* fall through */
case OP_NEQ:
case OP_FLAGCMP:
if (!datatype_equal(left->dtype, right->dtype))
@@ -1046,10 +1055,11 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
case EXPR_VERDICT:
case EXPR_EXTHDR:
case EXPR_META:
- case EXPR_CT:
return expr_evaluate_primary(ctx, expr);
case EXPR_PAYLOAD:
return expr_evaluate_payload(ctx, expr);
+ case EXPR_CT:
+ return expr_evaluate_ct(ctx, expr);
case EXPR_PREFIX:
return expr_evaluate_prefix(ctx, expr);
case EXPR_RANGE:
@@ -1117,7 +1127,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 +1143,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");
@@ -1174,6 +1184,8 @@ static int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
return stmt_evaluate_reject(ctx, stmt);
case STMT_NAT:
return stmt_evaluate_nat(ctx, stmt);
+ case STMT_QUEUE:
+ return 0;
default:
BUG("unknown statement type %s\n", stmt->ops->name);
}
@@ -1230,7 +1242,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) {
@@ -1261,6 +1273,7 @@ static uint32_t str2hooknum(uint32_t family, const char *hook)
case NFPROTO_IPV4:
case NFPROTO_BRIDGE:
case NFPROTO_IPV6:
+ case NFPROTO_INET:
/* These families have overlapping values for each hook */
if (!strcmp(hook, "prerouting"))
return NF_INET_PRE_ROUTING;
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),
},
};
diff --git a/src/main.c b/src/main.c
index e8be423d..14152398 100644
--- a/src/main.c
+++ b/src/main.c
@@ -111,7 +111,7 @@ static void show_help(const char *name)
" -a/--handle Output rule handle.\n"
" -I/--includepath <directory> Add <directory> to the paths searched for include files.\n"
#ifdef DEBUG
-" --debug <level [,level...]> Specify debugging level (scanner, parser, eval, netlink, all)\n"
+" --debug <level [,level...]> Specify debugging level (scanner, parser, eval, netlink, proto-ctx, all)\n"
#endif
"\n",
name);
@@ -139,6 +139,10 @@ static const struct {
.level = DEBUG_NETLINK,
},
{
+ .name = "proto-ctx",
+ .level = DEBUG_PROTO_CTX,
+ },
+ {
.name = "all",
.level = ~0,
},
diff --git a/src/meta.c b/src/meta.c
index 32f30121..d7b024b6 100644
--- a/src/meta.c
+++ b/src/meta.c
@@ -301,6 +301,10 @@ static const struct meta_template meta_templates[] = {
4 * 8, BYTEORDER_HOST_ENDIAN),
[NFT_META_PROTOCOL] = META_TEMPLATE("protocol", &ethertype_type,
2 * 8, BYTEORDER_BIG_ENDIAN),
+ [NFT_META_NFPROTO] = META_TEMPLATE("nfproto", &nfproto_type,
+ 1 * 8, BYTEORDER_HOST_ENDIAN),
+ [NFT_META_L4PROTO] = META_TEMPLATE("l4proto", &inet_protocol_type,
+ 1 * 8, BYTEORDER_HOST_ENDIAN),
[NFT_META_PRIORITY] = META_TEMPLATE("priority", &tchandle_type,
4 * 8, BYTEORDER_HOST_ENDIAN),
[NFT_META_MARK] = META_TEMPLATE("mark", &mark_type,
@@ -341,11 +345,60 @@ 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.
+ */
+static 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;
+
+ assert(expr->op == OP_EQ);
+
+ switch (left->meta.key) {
+ case NFT_META_IIFTYPE:
+ if (h->base < PROTO_BASE_NETWORK_HDR)
+ return;
+
+ desc = proto_dev_desc(mpz_get_uint16(right->value));
+ if (desc == NULL)
+ desc = &proto_unknown;
+
+ proto_ctx_update(ctx, PROTO_BASE_LL_HDR, &expr->location, desc);
+ break;
+ case NFT_META_NFPROTO:
+ desc = proto_find_upper(h->desc, mpz_get_uint8(right->value));
+ if (desc == NULL)
+ desc = &proto_unknown;
+
+ proto_ctx_update(ctx, PROTO_BASE_NETWORK_HDR, &expr->location, desc);
+ break;
+ case NFT_META_L4PROTO:
+ desc = proto_find_upper(&proto_inet_service,
+ mpz_get_uint8(right->value));
+ if (desc == NULL)
+ desc = &proto_unknown;
+
+ proto_ctx_update(ctx, PROTO_BASE_TRANSPORT_HDR, &expr->location, desc);
+ break;
+ default:
+ break;
+ }
+}
+
static const struct expr_ops meta_expr_ops = {
.type = EXPR_META,
.name = "meta",
.print = meta_expr_print,
.clone = meta_expr_clone,
+ .pctx_update = meta_expr_pctx_update,
};
struct expr *meta_expr_alloc(const struct location *loc, enum nft_meta_keys key)
@@ -356,6 +409,23 @@ struct expr *meta_expr_alloc(const struct location *loc, enum nft_meta_keys key)
expr = expr_alloc(loc, &meta_expr_ops, tmpl->dtype,
tmpl->byteorder, tmpl->len);
expr->meta.key = key;
+
+ switch (key) {
+ case NFT_META_IIFTYPE:
+ expr->flags |= EXPR_F_PROTOCOL;
+ break;
+ case NFT_META_NFPROTO:
+ expr->flags |= EXPR_F_PROTOCOL;
+ expr->meta.base = PROTO_BASE_LL_HDR;
+ break;
+ case NFT_META_L4PROTO:
+ expr->flags |= EXPR_F_PROTOCOL;
+ expr->meta.base = PROTO_BASE_NETWORK_HDR;
+ break;
+ default:
+ break;
+ }
+
return expr;
}
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 3d98131b..59b50745 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -325,9 +325,9 @@ static void netlink_parse_exthdr(struct netlink_parse_ctx *ctx,
expr);
}
-static void netlink_parse_meta(struct netlink_parse_ctx *ctx,
- const struct location *loc,
- const struct nft_rule_expr *nle)
+static void netlink_parse_meta_dreg(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nft_rule_expr *nle)
{
struct expr *expr;
@@ -338,6 +338,33 @@ static void netlink_parse_meta(struct netlink_parse_ctx *ctx,
expr);
}
+static void netlink_parse_meta_sreg(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nft_rule_expr *nle)
+{
+ struct stmt *stmt;
+ struct expr *expr;
+
+ expr = netlink_get_register(ctx, loc,
+ nft_rule_expr_get_u8(nle, NFT_EXPR_META_SREG));
+ stmt = meta_stmt_alloc(loc,
+ nft_rule_expr_get_u8(nle, NFT_EXPR_META_KEY),
+ expr);
+ expr_set_type(expr, stmt->meta.tmpl->dtype, stmt->meta.tmpl->byteorder);
+
+ list_add_tail(&stmt->list, &ctx->rule->stmts);
+}
+
+static void netlink_parse_meta(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nft_rule_expr *nle)
+{
+ if (nft_rule_expr_is_set(nle, NFT_EXPR_META_DREG))
+ netlink_parse_meta_dreg(ctx, loc, nle);
+ else
+ netlink_parse_meta_sreg(ctx, loc, nle);
+}
+
static void netlink_parse_ct(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nft_rule_expr *nle)
@@ -481,6 +508,20 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
list_add_tail(&stmt->list, &ctx->rule->stmts);
}
+static void netlink_parse_queue(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nft_rule_expr *nle)
+{
+ struct stmt *stmt;
+
+ stmt = queue_stmt_alloc(loc);
+ stmt->queue.queuenum = nft_rule_expr_get_u16(nle, NFT_EXPR_QUEUE_NUM);
+ stmt->queue.queues_total =
+ nft_rule_expr_get_u16(nle, NFT_EXPR_QUEUE_TOTAL);
+ stmt->queue.flags = nft_rule_expr_get_u16(nle, NFT_EXPR_QUEUE_FLAGS);
+ list_add_tail(&stmt->list, &ctx->rule->stmts);
+}
+
static const struct {
const char *name;
void (*parse)(struct netlink_parse_ctx *ctx,
@@ -501,6 +542,7 @@ static const struct {
{ .name = "limit", .parse = netlink_parse_limit },
{ .name = "reject", .parse = netlink_parse_reject },
{ .name = "nat", .parse = netlink_parse_nat },
+ { .name = "queue", .parse = netlink_parse_queue },
};
static const struct input_descriptor indesc_netlink = {
@@ -531,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;
};
@@ -541,15 +583,24 @@ 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);
stmt_free(ctx->pdep);
+ ctx->pbase = PROTO_BASE_INVALID;
ctx->pdep = NULL;
}
}
+static void payload_dependency_store(struct rule_pp_ctx *ctx,
+ struct stmt *stmt,
+ enum proto_bases base)
+{
+ ctx->pbase = base;
+ ctx->pdep = stmt;
+}
+
static void payload_match_postprocess(struct rule_pp_ctx *ctx,
struct stmt *stmt, struct expr *expr)
{
@@ -570,7 +621,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);
+ left->ops->pctx_update(&ctx->pctx, nexpr);
nstmt = expr_stmt_alloc(&stmt->location, nexpr);
list_add_tail(&nstmt->list, &stmt->list);
@@ -579,11 +630,11 @@ 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 &&
- left->payload.flags & PAYLOAD_PROTOCOL_EXPR) {
- ctx->pbase = left->payload.base;
- ctx->pdep = nstmt;
- } else
+ if (ctx->pbase == PROTO_BASE_INVALID &&
+ left->flags & EXPR_F_PROTOCOL)
+ payload_dependency_store(ctx, nstmt,
+ left->payload.base);
+ else
payload_dependency_kill(ctx, nexpr->left);
}
list_del(&stmt->list);
@@ -593,16 +644,24 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx,
payload_expr_complete(left, &ctx->pctx);
expr_set_type(expr->right, expr->left->dtype,
expr->left->byteorder);
+ payload_dependency_kill(ctx, expr->left);
break;
}
}
-static void meta_match_postprocess(struct payload_ctx *ctx,
+static void meta_match_postprocess(struct rule_pp_ctx *ctx,
+ struct stmt *stmt,
const struct expr *expr)
{
+ struct expr *left = expr->left;
+
switch (expr->op) {
case OP_EQ:
- payload_ctx_update_meta(ctx, expr);
+ expr->left->ops->pctx_update(&ctx->pctx, expr);
+
+ if (ctx->pbase == PROTO_BASE_INVALID &&
+ left->flags & EXPR_F_PROTOCOL)
+ payload_dependency_store(ctx, stmt, left->meta.base);
break;
default:
break;
@@ -723,7 +782,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx,
switch (expr->left->ops->type) {
case EXPR_META:
- meta_match_postprocess(&ctx->pctx, expr);
+ meta_match_postprocess(ctx, stmt, expr);
break;
case EXPR_BINOP:
relational_binop_postprocess(expr);
@@ -779,13 +838,17 @@ 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) {
case STMT_EXPRESSION:
expr_postprocess(&rctx, stmt, &stmt->expr);
break;
+ case STMT_META:
+ if (stmt->meta.expr != NULL)
+ expr_postprocess(&rctx, stmt, &stmt->meta.expr);
+ break;
case STMT_NAT:
if (stmt->nat.addr != NULL)
expr_postprocess(&rctx, stmt, &stmt->nat.addr);
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 79cb6a70..332383af 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -518,6 +518,8 @@ static void netlink_gen_meta_stmt(struct netlink_linearize_ctx *ctx,
release_register(ctx);
nle = alloc_nft_expr("meta");
+ nft_rule_expr_set_u32(nle, NFT_EXPR_META_SREG, sreg);
+ nft_rule_expr_set_u32(nle, NFT_EXPR_META_KEY, stmt->meta.key);
nft_rule_add_expr(ctx->nlr, nle);
}
@@ -634,6 +636,26 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
nft_rule_add_expr(ctx->nlr, nle);
}
+static void netlink_gen_queue_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nft_rule_expr *nle;
+
+ nle = alloc_nft_expr("queue");
+
+ nft_rule_expr_set_u16(nle, NFT_EXPR_QUEUE_NUM,
+ stmt->queue.queuenum);
+ if (stmt->queue.queues_total) {
+ nft_rule_expr_set_u16(nle, NFT_EXPR_QUEUE_TOTAL,
+ stmt->queue.queues_total);
+ }
+ if (stmt->queue.flags) {
+ nft_rule_expr_set_u16(nle, NFT_EXPR_QUEUE_FLAGS,
+ stmt->queue.flags);
+ }
+ nft_rule_add_expr(ctx->nlr, nle);
+}
+
static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
const struct stmt *stmt)
{
@@ -654,6 +676,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
return netlink_gen_reject_stmt(ctx, stmt);
case STMT_NAT:
return netlink_gen_nat_stmt(ctx, stmt);
+ case STMT_QUEUE:
+ return netlink_gen_queue_stmt(ctx, stmt);
default:
BUG("unknown statement type %s\n", stmt->ops->name);
}
diff --git a/src/parser.y b/src/parser.y
index faa9a33f..e5610e5a 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -165,6 +165,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token MAP "map"
%token HANDLE "handle"
+%token INET "inet"
+
%token ADD "add"
%token INSERT "insert"
%token DELETE "delete"
@@ -179,7 +181,6 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token JUMP "jump"
%token GOTO "goto"
%token RETURN "return"
-%token QUEUE "queue"
%token <val> NUM "number"
%token <string> STRING "string"
@@ -279,6 +280,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token MH "mh"
%token META "meta"
+%token NFPROTO "nfproto"
+%token L4PROTO "l4proto"
%token MARK "mark"
%token IIF "iif"
%token IIFNAME "iifname"
@@ -329,6 +332,13 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token SNAT "snat"
%token DNAT "dnat"
+%token QUEUE "queue"
+%token QUEUENUM "num"
+%token QUEUETOTAL "total"
+%token QUEUEBYPASS "bypass"
+%token QUEUECPUFANOUT "fanout"
+%token OPTIONS "options"
+
%token POSITION "position"
%type <string> identifier string
@@ -376,6 +386,9 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%destructor { stmt_free($$); } reject_stmt
%type <stmt> nat_stmt nat_stmt_alloc
%destructor { stmt_free($$); } nat_stmt nat_stmt_alloc
+%type <stmt> queue_stmt queue_stmt_alloc
+%destructor { stmt_free($$); } queue_stmt queue_stmt_alloc
+%type <val> queue_flags queue_flag
%type <expr> symbol_expr verdict_expr integer_expr
%destructor { expr_free($$); } symbol_expr verdict_expr integer_expr
@@ -817,6 +830,7 @@ string : STRING
family_spec : /* empty */ { $$ = NFPROTO_IPV4; }
| IP { $$ = NFPROTO_IPV4; }
| IP6 { $$ = NFPROTO_IPV6; }
+ | INET { $$ = NFPROTO_INET; }
| ARP { $$ = NFPROTO_ARP; }
| BRIDGE { $$ = NFPROTO_BRIDGE; }
;
@@ -926,6 +940,7 @@ stmt : verdict_stmt
| limit_stmt
| reject_stmt
| nat_stmt
+ | queue_stmt
;
verdict_stmt : verdict_expr
@@ -1050,6 +1065,57 @@ nat_stmt_args : expr
}
;
+queue_stmt : queue_stmt_alloc
+ | queue_stmt_alloc queue_args
+ ;
+
+queue_stmt_alloc : QUEUE
+ {
+ $$ = queue_stmt_alloc(&@$);
+ }
+ ;
+
+queue_args : queue_arg
+ {
+ $<stmt>$ = $<stmt>0;
+ }
+ | queue_args queue_arg
+ ;
+
+queue_arg : QUEUENUM NUM
+ {
+ $<stmt>0->queue.queuenum = $2;
+ }
+ | QUEUETOTAL NUM
+ {
+ $<stmt>0->queue.queues_total = $2;
+ }
+ | OPTIONS queue_flags
+ {
+ $<stmt>0->queue.flags = $2;
+ }
+ ;
+
+queue_flags : queue_flag
+ {
+ $$ = $1;
+ }
+ | queue_flags COMMA queue_flag
+ {
+ $$ |= $1 | $3;
+ }
+ ;
+
+queue_flag : QUEUEBYPASS
+ {
+ $$ = NFT_QUEUE_FLAG_BYPASS;
+ }
+ | QUEUECPUFANOUT
+ {
+ $$ = NFT_QUEUE_FLAG_CPU_FANOUT;
+ }
+ ;
+
match_stmt : relational_expr
{
$$ = expr_stmt_alloc(&@$, $1);
@@ -1286,10 +1352,6 @@ verdict_expr : ACCEPT
{
$$ = verdict_expr_alloc(&@$, NF_DROP, NULL);
}
- | QUEUE
- {
- $$ = verdict_expr_alloc(&@$, NF_QUEUE, NULL);
- }
| CONTINUE
{
$$ = verdict_expr_alloc(&@$, NFT_CONTINUE, NULL);
@@ -1315,6 +1377,8 @@ meta_expr : META meta_key
;
meta_key : LENGTH { $$ = NFT_META_LEN; }
+ | NFPROTO { $$ = NFT_META_NFPROTO; }
+ | L4PROTO { $$ = NFT_META_L4PROTO; }
| PROTOCOL { $$ = NFT_META_PROTOCOL; }
| PRIORITY { $$ = NFT_META_PRIORITY; }
| MARK { $$ = NFT_META_MARK; }
@@ -1386,14 +1450,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);
}
;
@@ -1404,7 +1468,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);
}
;
@@ -1416,7 +1480,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);
}
;
@@ -1429,7 +1493,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);
}
;
@@ -1448,7 +1512,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
{
@@ -1470,7 +1534,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);
}
;
@@ -1485,7 +1549,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
{
@@ -1508,7 +1572,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
{
@@ -1528,7 +1592,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
{
@@ -1545,7 +1609,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
{
@@ -1563,7 +1627,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
{
@@ -1582,7 +1646,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
{
@@ -1601,7 +1665,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
{
@@ -1626,7 +1690,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
{
@@ -1644,7 +1708,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 ea0d4e26..a312e079 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);
}
@@ -69,7 +46,30 @@ static void payload_expr_clone(struct expr *new, const struct expr *expr)
new->payload.tmpl = expr->payload.tmpl;
new->payload.base = expr->payload.base;
new->payload.offset = expr->payload.offset;
- new->payload.flags = expr->payload.flags;
+}
+
+/**
+ * payload_expr_pctx_update - update protocol context based on payload match
+ *
+ * @ctx: protocol context
+ * @expr: relational payload expression
+ *
+ * Update protocol context for relational payload expressions.
+ */
+static void payload_expr_pctx_update(struct proto_ctx *ctx,
+ const struct expr *expr)
+{
+ const struct expr *left = expr->left, *right = expr->right;
+ 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 = proto_find_upper(base, mpz_get_uint32(right->value));
+
+ proto_ctx_update(ctx, left->payload.base + 1, &expr->location, desc);
}
static const struct expr_ops payload_expr_ops = {
@@ -77,14 +77,15 @@ static const struct expr_ops payload_expr_ops = {
.name = "payload",
.print = payload_expr_print,
.clone = payload_expr_clone,
+ .pctx_update = payload_expr_pctx_update,
};
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;
@@ -92,23 +93,25 @@ struct expr *payload_expr_alloc(const struct location *loc,
tmpl = &desc->templates[type];
base = desc->base;
if (type == desc->protocol_key)
- flags = PAYLOAD_PROTOCOL_EXPR;
+ 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,
tmpl->dtype->byteorder, tmpl->len);
+ expr->flags |= flags;
+
expr->payload.desc = desc;
expr->payload.tmpl = tmpl;
expr->payload.base = base;
expr->payload.offset = tmpl->offset;
- expr->payload.flags = flags;
+
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;
@@ -117,157 +120,6 @@ 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
- *
- * @ctx: payload context
- * @expr: relational payload expression
- *
- * Update payload context for relational payload expressions.
- */
-void payload_ctx_update(struct payload_ctx *ctx, const struct expr *expr)
-{
- const struct expr *left = expr->left, *right = expr->right;
- const struct payload_desc *base, *desc;
-
- if (!(left->payload.flags & PAYLOAD_PROTOCOL_EXPR))
- return;
-
- assert(expr->op == OP_EQ);
- base = ctx->protocol[left->payload.base].desc;
- desc = payload_select_proto(base, mpz_get_uint32(right->value));
-
- ctx->protocol[left->payload.base + 1].location = expr->location;
- ctx->protocol[left->payload.base + 1].desc = desc;
-}
-
-/**
* payload_gen_dependency - generate match expression on payload dependency
*
* @ctx: evaluation context
@@ -293,9 +145,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;
@@ -306,7 +158,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");
@@ -322,26 +174,36 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
}
desc = ctx->pctx.protocol[expr->payload.base - 1].desc;
+ /* Special case for mixed IPv4/IPv6 tables: use meta L4 proto */
+ if (desc == NULL &&
+ ctx->pctx.family == NFPROTO_INET &&
+ expr->payload.base == PROTO_BASE_TRANSPORT_HDR)
+ desc = &proto_inet_service;
+
if (desc == NULL)
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",
desc->name, expr->payload.desc->name);
tmpl = &desc->templates[desc->protocol_key];
- left = payload_expr_alloc(&expr->location, desc, desc->protocol_key);
+ if (tmpl->meta_key)
+ left = meta_expr_alloc(&expr->location, tmpl->meta_key);
+ else
+ left = payload_expr_alloc(&expr->location, desc, desc->protocol_key);
+
right = constant_expr_alloc(&expr->location, tmpl->dtype,
BYTEORDER_HOST_ENDIAN,
tmpl->len, &protocol);
dep = relational_expr_alloc(&expr->location, OP_EQ, left, right);
- payload_ctx_update(&ctx->pctx, dep);
+ left->ops->pctx_update(&ctx->pctx, dep);
*res = dep;
return 0;
}
@@ -350,15 +212,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);
@@ -386,7 +248,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.
@@ -395,10 +257,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;
@@ -464,590 +326,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", &ethertype_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", &ethertype_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, &ethertype_tbl, res);
-}
-
-static void ethertype_print(const struct expr *expr)
-{
- return symbolic_constant_print(&ethertype_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, &ethertype_type, __member)
-#define ETHHDR_ADDR(__name, __member) \
- ETHHDR_TEMPLATE(__name, &etheraddr_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(&ethertype_type);
- datatype_register(&icmp6_type_type);
-}
diff --git a/src/proto.c b/src/proto.c
new file mode 100644
index 00000000..56fb7930
--- /dev/null
+++ b/src/proto.c
@@ -0,0 +1,814 @@
+/*
+ * 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_INET] = HOOK_PROTO_DESC(PROTO_BASE_LL_HDR, &proto_inet),
+ [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),
+};
+
+static void proto_ctx_debug(const struct proto_ctx *ctx, enum proto_bases base)
+{
+#ifdef DEBUG
+ unsigned int i;
+
+ if (!(debug_level & DEBUG_PROTO_CTX))
+ return;
+
+ pr_debug("update %s protocol context:\n", proto_base_names[base]);
+ for (i = PROTO_BASE_LL_HDR; i <= PROTO_BASE_MAX; i++) {
+ pr_debug(" %-20s: %s%s\n",
+ proto_base_names[i],
+ ctx->protocol[i].desc ? ctx->protocol[i].desc->name :
+ "none",
+ i == base ? " <-" : "");
+ }
+ pr_debug("\n");
+#endif
+}
+
+/**
+ * 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;
+
+ proto_ctx_debug(ctx, h->base);
+}
+
+/**
+ * proto_ctx_update: update protocol context for given protocol base
+ *
+ * @ctx: protocol context
+ * @base: protocol base
+ * @loc: location of the relational expression definiting the context
+ * @desc: protocol description for the given layer
+ */
+void proto_ctx_update(struct proto_ctx *ctx, enum proto_bases base,
+ const struct location *loc,
+ const struct proto_desc *desc)
+{
+ ctx->protocol[base].location = *loc;
+ ctx->protocol[base].desc = desc;
+
+ proto_ctx_debug(ctx, base);
+}
+
+#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),
+ },
+};
+
+/*
+ * Dummy protocol for mixed IPv4/IPv6 tables. The protocol is set at the link
+ * layer header, the upper layer protocols are IPv4 and IPv6.
+ */
+
+const struct proto_desc proto_inet = {
+ .name = "inet",
+ .base = PROTO_BASE_LL_HDR,
+ .protocols = {
+ PROTO_LINK(NFPROTO_IPV4, &proto_ip),
+ PROTO_LINK(NFPROTO_IPV6, &proto_ip6),
+ },
+ .templates = {
+ [0] = PROTO_META_TEMPLATE("nfproto", &nfproto_type, NFT_META_NFPROTO, 8),
+ },
+};
+
+/*
+ * Dummy protocol for cases where the network layer protocol isn't known
+ * (IPv4 or IPv6), The higher layer protocols are the protocols common to
+ * both.
+ */
+
+const struct proto_desc proto_inet_service = {
+ .name = "inet-service",
+ .base = PROTO_BASE_TRANSPORT_HDR,
+ .protocol_key = 0,
+ .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 = {
+ [0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8),
+ },
+};
+
+/*
+ * 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", &ethertype_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", &ethertype_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, &ethertype_tbl, res);
+}
+
+static void ethertype_print(const struct expr *expr)
+{
+ return symbolic_constant_print(&ethertype_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, &ethertype_type, __member)
+#define ETHHDR_ADDR(__name, __member) \
+ ETHHDR_TEMPLATE(__name, &etheraddr_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(&ethertype_type);
+ datatype_register(&icmp6_type_type);
+}
diff --git a/src/rule.c b/src/rule.c
index ec8b6a48..a16c2de7 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -276,6 +276,8 @@ static const char *family2str(unsigned int family)
return "ip";
case NFPROTO_IPV6:
return "ip6";
+ case NFPROTO_INET:
+ return "inet";
case NFPROTO_ARP:
return "arp";
case NFPROTO_BRIDGE:
@@ -292,6 +294,7 @@ static const char *hooknum2str(unsigned int family, unsigned int hooknum)
case NFPROTO_IPV4:
case NFPROTO_BRIDGE:
case NFPROTO_IPV6:
+ case NFPROTO_INET:
switch (hooknum) {
case NF_INET_PRE_ROUTING:
return "prerouting";
diff --git a/src/scanner.l b/src/scanner.l
index 13b0ce8c..5a5ec723 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -233,7 +233,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"jump" { return JUMP; }
"goto" { return GOTO; }
"return" { return RETURN; }
-"queue" { return QUEUE; }
+
+"inet" { return INET; }
"add" { return ADD; }
"insert" { return INSERT; }
@@ -254,6 +255,13 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"snaplen" { return SNAPLEN; }
"queue-threshold" { return QUEUE_THRESHOLD; }
+"queue" { return QUEUE;}
+"num" { return QUEUENUM;}
+"total" { return QUEUETOTAL;}
+"bypass" { return QUEUEBYPASS;}
+"fanout" { return QUEUECPUFANOUT;}
+"options" { return OPTIONS;}
+
"limit" { return LIMIT; }
"rate" { return RATE; }
@@ -362,6 +370,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"mh" { return MH; }
"meta" { return META; }
+"nfproto" { return NFPROTO; }
+"l4proto" { return L4PROTO; }
"mark" { return MARK; }
"iif" { return IIF; }
"iifname" { return IIFNAME; }
diff --git a/src/statement.c b/src/statement.c
index d18e0340..3fdd9e2d 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -172,6 +172,37 @@ struct stmt *limit_stmt_alloc(const struct location *loc)
return stmt_alloc(loc, &limit_stmt_ops);
}
+static void queue_stmt_print(const struct stmt *stmt)
+{
+ int one = 0;
+
+ printf("queue num %u total %u",
+ stmt->queue.queuenum, stmt->queue.queues_total);
+ if (stmt->queue.flags)
+ printf(" options ");
+ if (stmt->queue.flags & NFT_QUEUE_FLAG_BYPASS) {
+ printf("bypass");
+ one = 1;
+ }
+ if (stmt->queue.flags & NFT_QUEUE_FLAG_CPU_FANOUT) {
+ if (one)
+ printf (",");
+ printf("fanout");
+ }
+
+}
+
+static const struct stmt_ops queue_stmt_ops = {
+ .type = STMT_QUEUE,
+ .name = "queue",
+ .print = queue_stmt_print,
+};
+
+struct stmt *queue_stmt_alloc(const struct location *loc)
+{
+ return stmt_alloc(loc, &queue_stmt_ops);
+}
+
static void reject_stmt_print(const struct stmt *stmt)
{
printf("reject");