diff options
author | Vadim Kochan <vadim4j@gmail.com> | 2017-06-01 13:12:29 +0300 |
---|---|---|
committer | Tobias Klauser <tklauser@distanz.ch> | 2017-06-02 09:15:32 +0200 |
commit | e6c1b6ca7fd51a9b7d2b3c597cd9731b59330032 (patch) | |
tree | fb0b0c28179a60fd752090fd9b1f79dadb1308ea | |
parent | 9d5e303a998e4618d492c9d0befb09e3cd3d746b (diff) |
trafgen: parser: Add syntax to generate DNS header
Add new syntax for DNS header generation via 'dns()' proto function.
The fields are supported:
id - 16 bit identifier
qr - message is a query(0) or response(1)
op|oper - specified kind of query
aanswer - authoritative answer flag
trunc - message was truncated flag
rdesired - recursion desired flag
ravail - recursion available flag
zero - reserved for future use
rcode - response code
qdcount - number of entries in question section
ancount - number of entries in answer section
nscount - number of entries in authority section
arcount - number of entries in additional section
Also there are functions to generate DNS sections:
'qry()' function to generate separate query entry:
name - variable domain name
type - type of the query
class - class of the query
'ans()', 'auth()', 'add' functions to generate separate answer,
authoritative, adidditional entry with the same fields layout:
name - variable domain name
type - resource record type
class - class of the data
ttl - time interval that the record may be cached
len - length of data
data - variable length of bytes
All the DNS section entries will be automaticlly sorted by DNS proto API
in the way which is required by DNS header:
query entries
answer entries
authoritative entries
additional entries
'name' field in qry/ans/auth/add functions is automatically converted to
FQDN format if it was specified as "string".
There are also added functions to simplify the way of filling
some often used RR types for using them inside ans/auth/add functions:
addr(ipv4_addr | ipv6_addr) - fills the following RR fields:
len - 4 or 16 depends on IPv4 or IPv6 address was specified
data - is filled with IPv4 or IPv6 address
type - 1 for IPv4 address, 28 - for IPv6
ns(string)
type - 2
cname(string)
type - 5
ptr(string)
type - 12
EXAMPLES:
{
dns(qr=1,
auth(name="ns1", ns("ns1.org")),
ans(name="www.google.com", cname("google.com")),
auth(name="aa", ns("bb")),
qry(name="www.google.com"))
}
{
dns(qr=1, ans(name="www.google.com", addr(1.2.3.4)))
}
{
dns(qr=1, ans(name="www.google.com", addr(1::)))
}
Signed-off-by: Vadim Kochan <vadim4j@gmail.com>
Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
-rw-r--r-- | trafgen_lexer.l | 24 | ||||
-rw-r--r-- | trafgen_parser.y | 193 |
2 files changed, 217 insertions, 0 deletions
diff --git a/trafgen_lexer.l b/trafgen_lexer.l index cf67c74..da072e1 100644 --- a/trafgen_lexer.l +++ b/trafgen_lexer.l @@ -239,6 +239,29 @@ ip6_addr ({v680}|{v67}|{v66}|{v65}|{v64}|{v63}|{v62}|{v61}|{v60}) "win"|"window" { return K_WINDOW; } "urgptr" { return K_URG_PTR; } + /* DNS */ +"qr" { return K_QR; } +"aa"|"aanswer" { return K_AANSWER; } +"trunc" { return K_TRUNC; } +"ravail" { return K_RAVAIL; } +"rdesired" { return K_RDESIRED; } +"zero" { return K_ZERO; } +"rc"|"rcode" { return K_RCODE; } +"qdcount" { return K_QDCOUNT; } +"ancount" { return K_ANCOUNT; } +"nscount" { return K_NSCOUNT; } +"arcount" { return K_ARCOUNT; } +"name" { return K_NAME; } +"class" { return K_CLASS; } +"data" { return K_DATA; } +"qry"|"query" { return K_QUERY; } +"ans"|"answer" { return K_ANSWER; } +"auth" { return K_AUTH; } +"add" { return K_ADD; } +"ns" { return K_NS; } +"cname" { return K_CNAME; } +"ptr" { return K_PTR; } + "eth" { return K_ETH; } "pause" { return K_PAUSE; } "pfc" { return K_PFC; } @@ -251,6 +274,7 @@ ip6_addr ({v680}|{v67}|{v66}|{v65}|{v64}|{v63}|{v62}|{v61}|{v60}) "icmp6"|"icmpv6" { return K_ICMP6; } "udp" { return K_UDP; } "tcp" { return K_TCP; } +"dns" { return K_DNS; } [ ]*"-"[ ]* { return '-'; } [ ]*"+"[ ]* { return '+'; } diff --git a/trafgen_parser.y b/trafgen_parser.y index b4eedea..656c4f6 100644 --- a/trafgen_parser.y +++ b/trafgen_parser.y @@ -31,6 +31,7 @@ #include "trafgen_l2.h" #include "trafgen_l3.h" #include "trafgen_l4.h" +#include "trafgen_l7.h" #include "built_in.h" #include "die.h" #include "str.h" @@ -80,6 +81,8 @@ enum field_expr_type_t { FIELD_EXPR_INC = 1 << 4, FIELD_EXPR_RND = 1 << 5, FIELD_EXPR_OFFSET = 1 << 6, + FIELD_EXPR_STRING = 1 << 7, + FIELD_EXPR_FQDN = 1 << 8, }; struct proto_field_expr { @@ -91,6 +94,7 @@ struct proto_field_expr { struct in6_addr ip6_addr; long long int number; uint8_t mac[256]; + char *str; struct proto_field_func func; } val; }; @@ -434,6 +438,14 @@ static void proto_field_expr_eval(void) panic("Invalid value length %zu, can be 1,2 or 4\n", field->len); } else if (field_expr.type & FIELD_EXPR_MAC) { proto_field_set_bytes(field, field_expr.val.mac, 6); + } else if (field_expr.type & FIELD_EXPR_FQDN) { + char *fqdn = str2fqdn(field_expr.val.str); + proto_field_set_bytes(field, (uint8_t *) fqdn, strlen(fqdn) + 1); + xfree(field_expr.val.str); + xfree(fqdn); + } else if (field_expr.type & FIELD_EXPR_STRING) { + proto_field_set_string(field, field_expr.val.str); + xfree(field_expr.val.str); } else if (field_expr.type & FIELD_EXPR_IP4_ADDR) { proto_field_set_u32(field, field_expr.val.ip4_addr.s_addr); } else if (field_expr.type & FIELD_EXPR_IP6_ADDR) { @@ -472,6 +484,19 @@ static void field_index_validate(struct proto_field *field, uint16_t index, size } } +static void proto_push_sub_hdr(uint32_t id) +{ + hdr = proto_hdr_push_sub_header(hdr, id); +} + +static void proto_pop_sub_hdr(void) +{ + if (hdr->ops->header_finish) + hdr->ops->header_finish(hdr); + + hdr = hdr->parent; +} + %} %union { @@ -498,6 +523,10 @@ static void field_index_validate(struct proto_field *field, uint16_t index, size %token K_ADDR K_MTU +%token K_QR K_AANSWER K_TRUNC K_RAVAIL K_RDESIRED K_ZERO K_RCODE K_QDCOUNT K_ANCOUNT K_NSCOUNT K_ARCOUNT +%token K_QUERY K_ANSWER K_AUTH K_ADD +%token K_NAME K_CLASS K_DATA K_NS K_CNAME K_PTR + %token K_ETH %token K_PAUSE %token K_PFC @@ -506,6 +535,7 @@ static void field_index_validate(struct proto_field *field, uint16_t index, size %token K_IP4 K_IP6 %token K_ICMP4 K_ICMP6 %token K_UDP K_TCP +%token K_DNS %token ',' '{' '}' '(' ')' '[' ']' ':' '-' '+' '*' '/' '%' '&' '|' '<' '>' '^' @@ -738,6 +768,7 @@ proto | icmpv6_proto { } | udp_proto { } | tcp_proto { } + | dns_proto { } ; field_expr @@ -758,6 +789,9 @@ field_value_expr field_expr.val.number = $1; } | mac { field_expr.type |= FIELD_EXPR_MAC; memcpy(field_expr.val.mac, $1, sizeof(field_expr.val.mac)); } + | string { field_expr.type |= FIELD_EXPR_STRING; + field_expr.val.str = xstrdup($1 + 1); + field_expr.val.str[strlen($1 + 1) - 1] = '\0'; } | ip4_addr { field_expr.type |= FIELD_EXPR_IP4_ADDR; field_expr.val.ip4_addr = $1; } | ip6_addr { field_expr.type |= FIELD_EXPR_IP6_ADDR; @@ -1229,6 +1263,157 @@ tcp : K_TCP { proto_add(PROTO_TCP); } ; +dns_proto + : dns '(' dns_param_list ')' { } + ; + +dns_param_list + : { } + | dns_expr { } + | dns_expr delimiter dns_param_list { } + ; + +dns_field + : K_ID { proto_field_set(DNS_ID); } + | K_QR { proto_field_set(DNS_QR); } + | K_OPER { proto_field_set(DNS_OPCODE); } + | K_AANSWER { proto_field_set(DNS_AA); } + | K_TRUNC { proto_field_set(DNS_TC); } + | K_RDESIRED { proto_field_set(DNS_RD); } + | K_RAVAIL { proto_field_set(DNS_RA); } + | K_ZERO { proto_field_set(DNS_ZERO); } + | K_RCODE { proto_field_set(DNS_RCODE); } + | K_QDCOUNT { proto_field_set(DNS_QD_COUNT); } + | K_ANCOUNT { proto_field_set(DNS_AN_COUNT); } + | K_NSCOUNT { proto_field_set(DNS_NS_COUNT); } + | K_ARCOUNT { proto_field_set(DNS_AR_COUNT); } + ; + +dns_query + : K_QUERY { proto_push_sub_hdr(DNS_QUERY_HDR); } + ; + +dns_query_name + : K_NAME { proto_field_set(DNS_QUERY_NAME); } + ; + +dns_query_field + : K_TYPE { proto_field_set(DNS_QUERY_TYPE); } + | K_CLASS { proto_field_set(DNS_QUERY_CLASS); } + ; + +dns_query_expr + : dns_query_field field_expr skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | dns_query_field skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | dns_query_name field_expr skip_white '=' skip_white field_value_expr + { if (field_expr.type & FIELD_EXPR_STRING) + field_expr.type = FIELD_EXPR_FQDN; + proto_field_expr_eval(); } + | dns_query_name skip_white '=' skip_white field_value_expr + { if (field_expr.type & FIELD_EXPR_STRING) + field_expr.type = FIELD_EXPR_FQDN; + proto_field_expr_eval(); } + ; + +dns_query_param_list + : { } + | dns_query_expr { } + | dns_query_expr delimiter dns_query_param_list { } + ; + +dns_query_hdr + : dns_query '(' dns_query_param_list ')' { } + ; + +dns_rrecord + : K_ANSWER { proto_push_sub_hdr(DNS_ANSWER_HDR); } + | K_AUTH { proto_push_sub_hdr(DNS_AUTH_HDR); } + | K_ADD { proto_push_sub_hdr(DNS_ADD_HDR); } + ; + +dns_rrecord_name + : K_NAME { proto_field_set(DNS_RRECORD_NAME); } + ; + +dns_rrecord_data_addr + : ip4_addr + { proto_hdr_field_set_u32(hdr, DNS_RRECORD_DATA, $1.s_addr); + proto_hdr_field_set_be16(hdr, DNS_RRECORD_TYPE, 1); } + | ip6_addr + { proto_hdr_field_set_bytes(hdr, DNS_RRECORD_DATA, (uint8_t *)&$1.s6_addr, 16); + proto_hdr_field_set_be16(hdr, DNS_RRECORD_TYPE, 28); } + ; + +dns_rrecord_data_fqdn + : string + { char *str = xstrdup($1 + 1); + char *fqdn; + str[strlen($1 + 1) - 1] = '\0'; + fqdn = str2fqdn(str); + proto_hdr_field_set_bytes(hdr, DNS_RRECORD_DATA, (uint8_t *) fqdn, strlen(fqdn) + 1); + xfree(fqdn); } + ; + +dns_rrecord_data_expr + : K_ADDR '(' skip_white dns_rrecord_data_addr skip_white ')' + { } + | K_NS '(' skip_white dns_rrecord_data_fqdn skip_white ')' + { proto_hdr_field_set_be16(hdr, DNS_RRECORD_TYPE, 2); } + | K_CNAME '(' skip_white dns_rrecord_data_fqdn skip_white ')' + { proto_hdr_field_set_be16(hdr, DNS_RRECORD_TYPE, 5); } + | K_PTR '(' skip_white dns_rrecord_data_fqdn skip_white ')' + { proto_hdr_field_set_be16(hdr, DNS_RRECORD_TYPE, 12); } + ; + +dns_rrecord_field + : K_TYPE { proto_field_set(DNS_RRECORD_TYPE); } + | K_CLASS { proto_field_set(DNS_RRECORD_CLASS); } + | K_TTL { proto_field_set(DNS_RRECORD_TTL); } + | K_LEN { proto_field_set(DNS_RRECORD_LEN); } + | K_DATA { proto_field_set(DNS_RRECORD_DATA); } + ; + +dns_rrecord_expr + : dns_rrecord_field field_expr skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | dns_rrecord_field skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | dns_rrecord_name field_expr skip_white '=' skip_white field_value_expr + { if (field_expr.type & FIELD_EXPR_STRING) + field_expr.type = FIELD_EXPR_FQDN; + proto_field_expr_eval(); } + | dns_rrecord_name skip_white '=' skip_white field_value_expr + { if (field_expr.type & FIELD_EXPR_STRING) + field_expr.type = FIELD_EXPR_FQDN; + proto_field_expr_eval(); } + | dns_rrecord_data_expr + { } + ; + +dns_rrecord_param_list + : { } + | dns_rrecord_expr { } + | dns_rrecord_expr delimiter dns_rrecord_param_list { } + ; + +dns_rrecord_hdr + : dns_rrecord '(' dns_rrecord_param_list ')' { } + ; + +dns_expr + : dns_field field_expr skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | dns_field skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | dns_query_hdr { proto_pop_sub_hdr(); } + | dns_rrecord_hdr { proto_pop_sub_hdr(); } + ; + +dns + : K_DNS { proto_add(PROTO_DNS); } + ; %% static void finalize_packet(void) @@ -1281,9 +1466,17 @@ void cleanup_packets(void) for (j = 0; j < pkt->headers_count; j++) { struct proto_hdr *hdr = pkt->headers[j]; + int k; + + for (k = 0; k < hdr->sub_headers_count; k++) + xfree(hdr->sub_headers[k]); + + if (hdr->sub_headers) + xfree(hdr->sub_headers); if (hdr->fields) xfree(hdr->fields); + xfree(hdr); } } |