diff --git a/mio/lib/dns.c b/mio/lib/dns.c index e3482c9..6ca0934 100644 --- a/mio/lib/dns.c +++ b/mio/lib/dns.c @@ -126,7 +126,7 @@ struct mio_dnsc_t struct mio_dns_req_t { - mio_dns_msg_t* msg; + mio_dns_hdr_t* msg; /* source address */ /*mio_dns_req_t* prev; @@ -138,7 +138,7 @@ typedef struct mio_dns_req_t mio_dns_req_t; static int dns_on_read (mio_dev_sck_t* dev, const void* data, mio_iolen_t dlen, const mio_sckaddr_t* srcaddr) { mio_t* mio = dev->mio; - mio_dns_msg_t* msg; + mio_dns_hdr_t* msg; mio_uint16_t id; if (dlen < MIO_SIZEOF(*msg)) @@ -146,7 +146,7 @@ static int dns_on_read (mio_dev_sck_t* dev, const void* data, mio_iolen_t dlen, MIO_DEBUG0 (mio, "dns packet too small from ....\n"); /* TODO: add source packet */ return 0; /* drop */ } - msg = (mio_dns_msg_t*)data; + msg = (mio_dns_hdr_t*)data; if (!msg->qr) return 0; /* drop request */ id = mio_ntoh16(msg->id); @@ -219,7 +219,7 @@ void mio_dnsc_stop (mio_dnsc_t* dnsc) mio_freemem (mio, dnsc); } -static void release_req_msg (mio_dnsc_t* dnsc, mio_dns_msg_t* msg) +static void release_dns_msg (mio_dnsc_t* dnsc, mio_dns_hdr_t* msg) { mio_t* mio = dnsc->mio; void* msgbuf; @@ -229,17 +229,17 @@ static void release_req_msg (mio_dnsc_t* dnsc, mio_dns_msg_t* msg) mio_freemem (mio, msgbuf); } -static mio_dns_msg_t* build_req_msg (mio_dnsc_t* dnsc, mio_dns_bqr_t* qr, mio_oow_t qr_count, mio_dns_brr_t* rr, mio_oow_t rr_count, mio_dns_bedns_t* edns, mio_oow_t* xmsglen) +static mio_dns_hdr_t* build_dns_msg (mio_dnsc_t* dnsc, mio_dns_bdns_t* bdns, mio_dns_bqr_t* qr, mio_oow_t qr_count, mio_dns_brr_t* rr, mio_oow_t rr_count, mio_dns_bedns_t* edns, mio_oow_t* xmsglen) { mio_t* mio = dnsc->mio; mio_oow_t dnlen, msgbufsz, i; void* msgbuf; - mio_dns_msg_t* msg; + mio_dns_hdr_t* msg; mio_uint8_t* dn; mio_dns_qrtr_t* qrtr; mio_dns_rrtr_t* rrtr; int rr_sect; - mio_uint16_t edns_dlen; + mio_uint32_t edns_dlen; msgbufsz = MIO_SIZEOF(msgbufsz) + MIO_SIZEOF(*msg); @@ -259,15 +259,33 @@ static mio_dns_msg_t* build_req_msg (mio_dnsc_t* dnsc, mio_dns_bqr_t* qr, mio_oo edns_dlen = 0; if (edns) { + mio_dns_beopt_t* beopt; + msgbufsz += 1 + MIO_SIZEOF(*rrtr); /* edns0 OPT RR - 1 for the root name */ - for (i = 0; i < edns->olen; i++) + beopt = edns->beoptr; + for (i = 0; i < edns->beonum; i++) { - edns_dlen += 2 + edns->optr->dlen; - + edns_dlen += MIO_SIZEOF(mio_dns_eopt_t) + beopt->dlen; + if (edns_dlen > MIO_TYPE_MAX(mio_uint16_t)) + { + mio_seterrbfmt (mio, MIO_EINVAL, "edns options too large"); + return MIO_NULL; + } + beopt++; } + msgbufsz += edns_dlen; } + else + { + if (bdns->rcode > 0x0F) + { + /* rcode is larger than 4 bits. but edns info is not provided */ + mio_seterrbfmt (mio, MIO_EINVAL, "rcode too large without edns - %d", bdns->rcode); + return MIO_NULL; + } + } msgbufsz = MIO_ALIGN_POW2(msgbufsz, 64); @@ -276,7 +294,7 @@ static mio_dns_msg_t* build_req_msg (mio_dnsc_t* dnsc, mio_dns_bqr_t* qr, mio_oo if (!msgbuf) return MIO_NULL; *(mio_oow_t*)msgbuf = msgbufsz; /* record the buffer size in the first word */ - msg = (mio_dns_msg_t*)(msgbuf + MIO_SIZEOF(mio_oow_t)); /* actual message begins after the size word */ + msg = (mio_dns_hdr_t*)(msgbuf + MIO_SIZEOF(mio_oow_t)); /* actual message begins after the size word */ dn = (mio_uint8_t*)(msg + 1); for (i = 0; i < qr_count; i++) @@ -285,7 +303,7 @@ static mio_dns_msg_t* build_req_msg (mio_dnsc_t* dnsc, mio_dns_bqr_t* qr, mio_oo dnlen = to_dn((mio_dns_t*)dnsc, qr[i].qname, dn, mio_count_bcstr(qr[i].qname) + 2); if (dnlen <= 0) { - release_req_msg (dnsc, msg); + release_dns_msg (dnsc, msg); mio_seterrbfmt (mio, MIO_EINVAL, "invalid domain name - %hs", qr[i].qname); return MIO_NULL; @@ -307,7 +325,7 @@ static mio_dns_msg_t* build_req_msg (mio_dnsc_t* dnsc, mio_dns_bqr_t* qr, mio_oo dnlen = to_dn((mio_dns_t*)dnsc, rr[i].qname, dn, mio_count_bcstr(rr[i].qname) + 2); if (dnlen <= 0) { - release_req_msg (dnsc, msg); + release_dns_msg (dnsc, msg); mio_seterrbfmt (mio, MIO_EINVAL, "invalid domain name - %hs", rr[i].qname); return MIO_NULL; } @@ -326,104 +344,92 @@ static mio_dns_msg_t* build_req_msg (mio_dnsc_t* dnsc, mio_dns_bqr_t* qr, mio_oo } rr_sect = rr_sect + 1; - ((mio_dns_msg_alt_t*)msg)->rrcount[rr_sect] = mio_hton16(match_count); + ((mio_dns_hdr_alt_t*)msg)->rrcount[rr_sect] = mio_hton16(match_count); } -/* TODO: add EDNS0 to request if requested ... - * add EDNS0 to response if request contains it */ if (edns) { + mio_dns_eopt_t* eopt; + mio_dns_beopt_t* beopt; + /* add EDNS0 OPT RR */ *dn = 0; /* root domain. as if to_dn("") is called */ rrtr = (mio_dns_rrtr_t*)(dn + 1); rrtr->qtype = MIO_CONST_HTON16(MIO_DNS_QTYPE_OPT); rrtr->qclass = mio_hton16(edns->uplen); - rrtr->ttl = MIO_CONST_HTON32(0); /* extended rcode, version, flags TODO: take edns->version */ - rrtr->dlen = mio_hton16(edns_dlen); - dn = (mio_uint8_t*)(rrtr + 1) + 0; + rrtr->ttl = mio_hton32(MIO_DNS_EDNS_MAKE_TTL(bdns->rcode, edns->version, edns->dnssecok)); + rrtr->dlen = mio_hton16((mio_uint16_t)edns_dlen); + dn = (mio_uint8_t*)(rrtr + 1); - for (i = 0; i < edns->olen; i++) + beopt = edns->beoptr; + eopt = (mio_dns_eopt_t*)dn; + + for (i = 0; i < edns->beonum; i++) { + eopt->code = mio_hton16(beopt->code); + eopt->dlen = mio_hton16(beopt->dlen); + MIO_MEMCPY (++eopt, beopt->dptr, beopt->dlen); + eopt = (mio_dns_eopt_t*)((mio_uint8_t*)eopt + beopt->dlen); + beopt++; } msg->arcount = mio_hton16((mio_ntoh16(msg->arcount) + 1)); - + dn += edns_dlen; } - msg->qr = (rr_count > 0); - msg->opcode = MIO_DNS_OPCODE_QUERY; msg->qdcount = mio_hton16(qr_count); + if (bdns->id < 0) + { + msg->id = mio_hton16(dnsc->seq); + dnsc->seq++; + } + else + { + msg->id = mio_hton16((mio_uint16_t)bdns->id); + } + + /*msg->qr = (rr_count > 0); + msg->opcode = MIO_DNS_OPCODE_QUERY;*/ + msg->qr = bdns->qr & 0x01; + msg->opcode = bdns->opcode & 0x0F; + msg->aa = bdns->aa & 0x01; + msg->tc = bdns->tc & 0x01; + msg->rd = bdns->rd & 0x01; + msg->ra = bdns->ra & 0x01; + msg->ad = bdns->ad & 0x01; + msg->cd = bdns->cd & 0x01; + msg->rcode = bdns->rcode & 0x0F; + *xmsglen = dn - (mio_uint8_t*)msg; return msg; /* return the pointer to the beginning of the actual message */ } - -static MIO_INLINE int send_req_with_single_rr (mio_dnsc_t* dnsc, mio_dns_bqr_t* qr) +int mio_dnsc_sendmsg (mio_dnsc_t* dnsc, mio_dns_bdns_t* bdns, mio_dns_bqr_t* qr, mio_oow_t qr_count, mio_dns_brr_t* rr, mio_oow_t rr_count, mio_dns_bedns_t* edns) { - mio_dns_msg_t* msg; + /* send a request or a response */ + mio_dns_hdr_t* msg; mio_oow_t msglen; + int n; - msg = build_req_msg(dnsc, qr, 1, MIO_NULL, 0, MIO_NULL, &msglen); + msg = build_dns_msg(dnsc, bdns, qr, qr_count, rr, rr_count, edns, &msglen); if (!msg) return -1; - msg->rd = 1; - msg->id = mio_hton16(dnsc->seq); - dnsc->seq++; + n = mio_dev_sck_write(dnsc->sck, msg, msglen, MIO_NULL, &dnsc->serveraddr); /* TODO: optionally, override dnsc->serveraddr */ -/* TODO: if response, set msg->ra, set msg->id with id in request */ - - mio_dev_sck_write(dnsc->sck, msg, msglen, MIO_NULL, &dnsc->serveraddr); /* TODO: optionally, override dnsc->serveraddr */ - - release_req_msg (dnsc, msg); - return 0; + release_dns_msg (dnsc, msg); + return n; } -int mio_dnsc_sendreq (mio_dnsc_t* dnsc, mio_dns_bqr_t* qr, mio_oow_t count) +int mio_dnsc_sendreq (mio_dnsc_t* dnsc, mio_dns_bdns_t* bdns, mio_dns_bqr_t* qr, mio_oow_t qr_count, mio_dns_bedns_t* edns) { -#if 1 + /* send requests without resource record */ mio_oow_t i; - - for (i = 0; i < count; i++) + for (i = 0; i < qr_count; i++) { - if (send_req_with_single_rr(dnsc, &qr[i]) <= -1) return -1; + if (mio_dnsc_sendmsg(dnsc, bdns, &qr[i], 1, MIO_NULL, 0, edns) <= -1) return -1; } return 0; -#else - mio_dns_msg_t* msg; - mio_oow_t msglen; - - msg = build_req_msg(dnsc, qr, count, MIO_NULL, &msglen); - if (!msg) return -1; - - msg->rd = 1; - msg->id = mio_hton16(dnsc->seq); - dnsc->seq++; -/* TODO: if response, set msg->ra, set msg->id with id in request */ - - mio_dev_sck_write(dnsc->sck, msg, msglen, MIO_NULL, &dnsc->serveraddr); /* TODO: optionally, override dnsc->serveraddr */ - - release_req_msg (dnsc, msg); - return 0; -#endif -} - -int mio_dnsc_sendrep (mio_dnsc_t* dnsc, mio_dns_bqr_t* qr, mio_oow_t qr_count, mio_dns_brr_t* rr, mio_oow_t rr_count) -{ - mio_dns_msg_t* msg; - mio_oow_t msglen; - - msg = build_req_msg(dnsc, qr, qr_count, rr, rr_count, MIO_NULL, &msglen); - if (!msg) return -1; - - msg->rd = 1; - msg->ra = 1; - /* TODO: msg->id = copy from request */ - - mio_dev_sck_write(dnsc->sck, msg, msglen, MIO_NULL, &dnsc->serveraddr); /* TODO: optionally, override dnsc->serveraddr */ - - release_req_msg (dnsc, msg); - return 0; } #if 0 diff --git a/mio/lib/main.c b/mio/lib/main.c index 2760d80..598db59 100644 --- a/mio/lib/main.c +++ b/mio/lib/main.c @@ -825,8 +825,54 @@ for (i = 0; i < 5; i++) { MIO_DNS_RR_PART_AUTHORITY, "dns.miflux.com", MIO_DNS_QTYPE_NS, MIO_DNS_QCLASS_IN, 86400, 0, MIO_NULL } }; - mio_dnsc_sendreq (dnsc, qrs, MIO_COUNTOF(qrs)); - mio_dnsc_sendrep (dnsc, qrs, MIO_COUNTOF(qrs), rrs, MIO_COUNTOF(rrs)); + mio_dns_beopt_t beopt[] = + { + { MIO_DNS_EOPT_COOKIE, 8, "\x01\x02\x03\x04\0x05\x06\0x07\0x08" }, + { MIO_DNS_EOPT_NSID, 0, MIO_NULL } + }; + + mio_dns_bedns_t qedns = + { + 4096, /* uplen */ + + 0, /* edns version */ + 0, /* dnssec ok */ + + MIO_COUNTOF(beopt), /* number of edns options */ + beopt + }; + + mio_dns_bdns_t qhdr = + { + -1, /* id */ + 0, /* qr */ + MIO_DNS_OPCODE_QUERY, /* opcode */ + 0, /* aa */ + 0, /* tc */ + 1, /* rd */ + 0, /* ra */ + 0, /* ad */ + 0, /* cd */ + MIO_DNS_RCODE_NOERROR /* rcode */ + }; + + mio_dns_bdns_t rhdr = + { + 0x1234, /* id */ + 1, /* qr */ + MIO_DNS_OPCODE_QUERY, /* opcode */ + + 0, /* aa */ + 0, /* tc */ + 0, /* rd */ + 1, /* ra */ + 0, /* ad */ + 0, /* cd */ + MIO_DNS_RCODE_BADCOOKIE /* rcode */ + }; + + mio_dnsc_sendreq (dnsc, &qhdr, qrs, MIO_COUNTOF(qrs), &qedns); + mio_dnsc_sendmsg (dnsc, &rhdr, qrs, MIO_COUNTOF(qrs), rrs, MIO_COUNTOF(rrs), &qedns); } mio_loop (mio); diff --git a/mio/lib/mio-dns.h b/mio/lib/mio-dns.h index c9a8bb7..02e997e 100644 --- a/mio/lib/mio-dns.h +++ b/mio/lib/mio-dns.h @@ -96,11 +96,26 @@ enum mio_dns_qclass_t }; typedef enum mio_dns_qclass_t mio_dns_qclass_t; +enum mio_dns_eopt_code_t +{ + MIO_DNS_EOPT_NSID = 3, + MIO_DNS_EOPT_DAU = 5, + MIO_DNS_EOPT_DHU = 6, + MIO_DNS_EOPT_N3U = 7, + MIO_DNS_EOPT_ECS = 8, + MIO_DNS_EOPT_EXPIRE = 9, + MIO_DNS_EOPT_COOKIE = 10, + MIO_DNS_EOPT_TCPKEEPALIVE = 11, + MIO_DNS_EOPT_PADDING = 12, + MIO_DNS_EOPT_CHAIN = 13, + MIO_DNS_EOPT_KEYTAG = 14, +}; +typedef enum mio_dns_eopt_code_t mio_dns_eopt_code_t; + #include -struct mio_dns_msg_t +struct mio_dns_hdr_t { mio_uint16_t id; - #if defined(MIO_ENDIAN_BIG) mio_uint16_t qr: 1; /* query(0), answer(1) */ mio_uint16_t opcode: 4; /* operation type */ @@ -112,7 +127,7 @@ struct mio_dns_msg_t mio_uint16_t unused_1: 1; mio_uint16_t ad: 1; /* authentication data - dnssec */ mio_uint16_t cd: 1; /* checking disabled - dnssec */ - mio_uint16_t rcode: 4; + mio_uint16_t rcode: 4; /* reply code - for reply only */ #else mio_uint16_t rd: 1; mio_uint16_t tc: 1; @@ -132,15 +147,15 @@ struct mio_dns_msg_t mio_uint16_t nscount; /* number of name servers (authority part. only NS types) */ mio_uint16_t arcount; /* number of additional resource (additional part) */ }; -typedef struct mio_dns_msg_t mio_dns_msg_t; +typedef struct mio_dns_hdr_t mio_dns_hdr_t; -struct mio_dns_msg_alt_t +struct mio_dns_hdr_alt_t { mio_uint16_t id; mio_uint16_t flags; mio_uint16_t rrcount[4]; }; -typedef struct mio_dns_msg_alt_t mio_dns_msg_alt_t; +typedef struct mio_dns_hdr_alt_t mio_dns_hdr_alt_t; /* question * name, qtype, qclass * answer @@ -168,11 +183,43 @@ struct mio_dns_rrtr_t }; typedef struct mio_dns_rrtr_t mio_dns_rrtr_t; +struct mio_dns_eopt_t +{ + mio_uint16_t code; + mio_uint16_t dlen; + /* actual data if if dlen > 0 */ +}; +typedef struct mio_dns_eopt_t mio_dns_eopt_t; + #include typedef struct mio_dnss_t mio_dnss_t; typedef struct mio_dnsc_t mio_dnsc_t; +/* +#define MIO_DNS_HDR_MAKE_FLAGS(qr,opcode,aa,tc,rd,ra,ad,cd,rcode) \ + ((((qr) & 0x01) << 15) | (((opcode) & 0x0F) << 14) | (((aa) & 0x01) << 10) | (((tc) & 0x01) << 9) | \ + (((rd) & 0x01) << 8) | (((ra) & 0x01) << 7) | (((ad) & 0x01) << 5) | (((cd) & 0x01) << 4) | ((rcode) & 0x0F)) +*/ + +/* breakdown of the dns message id and flags */ +struct mio_dns_bdns_t +{ + int id; /* auto-assign if negative. */ + + mio_uint8_t qr; /* query(0), answer(1) */ + mio_uint8_t opcode; /* operation type */ + mio_uint8_t aa; /* authoritative answer */ + mio_uint8_t tc; /* truncated. response too large for UDP */ + mio_uint8_t rd; /* recursion desired */ + + mio_uint8_t ra; /* recursion available */ + mio_uint8_t ad; /* authentication data - dnssec */ + mio_uint8_t cd; /* checking disabled - dnssec */ + mio_uint8_t rcode; /* reply code - for reply only */ +}; +typedef struct mio_dns_bdns_t mio_dns_bdns_t; + /* breakdown of question record */ struct mio_dns_bqr_t { @@ -204,25 +251,30 @@ struct mio_dns_brr_t }; typedef struct mio_dns_brr_t mio_dns_brr_t; -struct mio_dns_bedns_opt_t +struct mio_dns_beopt_t { - mio_uint16_t dtype; + mio_uint16_t code; mio_uint16_t dlen; void* dptr; }; -typedef struct mio_dns_bedns_opt_t mio_dns_bedns_opt_t; +typedef struct mio_dns_beopt_t mio_dns_beopt_t; + +/* the full rcode must be given. the macro takes the upper 8 bits */ +#define MIO_DNS_EDNS_MAKE_TTL(rcode,version,dnssecok) ((((((mio_uint32_t)rcode) >> 4) & 0xFF) << 24) | (((mio_uint32_t)version & 0xFF) << 16) | (((mio_uint32_t)dnssecok & 0x1) << 15)) struct mio_dns_bedns_t { - mio_uint16_t uplen; /* udp payload len */ - mio_uint8_t version; + mio_uint16_t uplen; /* udp payload len - will be placed in the qclass field of RR. */ - mio_oow_t olen; /* option count*/ - mio_dns_bedns_opt_t* optr; + /* the ttl field(32 bits) of RR holds extended rcode, version, dnssecok */ + mio_uint8_t version; + mio_uint8_t dnssecok; + + mio_oow_t beonum; /* option count */ + mio_dns_beopt_t* beoptr; }; typedef struct mio_dns_bedns_t mio_dns_bedns_t; - #if defined(__cplusplus) extern "C" { #endif @@ -236,17 +288,21 @@ MIO_EXPORT void mio_dnsc_stop ( ); MIO_EXPORT int mio_dnsc_sendreq ( - mio_dnsc_t* dnsc, - mio_dns_bqr_t* qr, - mio_oow_t qr_count + mio_dnsc_t* dnsc, + mio_dns_bdns_t* bdns, + mio_dns_bqr_t* qr, + mio_oow_t qr_count, + mio_dns_bedns_t* edns ); -MIO_EXPORT int mio_dnsc_sendrep ( - mio_dnsc_t* dnsc, - mio_dns_bqr_t* qr, - mio_oow_t qr_count, - mio_dns_brr_t* rr, - mio_oow_t rr_count +MIO_EXPORT int mio_dnsc_sendmsg ( + mio_dnsc_t* dnsc, + mio_dns_bdns_t* bdns, + mio_dns_bqr_t* qr, + mio_oow_t qr_count, + mio_dns_brr_t* rr, + mio_oow_t rr_count, + mio_dns_bedns_t* edns ); #if defined(__cplusplus)