123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093 |
- /*************************************************************************
- *
- * Copyright (C) 2018-2025 Ruilin Peng (Nick) <[email protected]>.
- *
- * smartdns is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * smartdns is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #define _GNU_SOURCE
- #include "dns.h"
- #include "stringutil.h"
- #include "tlog.h"
- #include <arpa/inet.h>
- #include <fcntl.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <unistd.h>
- #define QR_MASK 0x8000
- #define OPCODE_MASK 0x7800
- #define AA_MASK 0x0400
- #define TC_MASK 0x0200
- #define RD_MASK 0x0100
- #define RA_MASK 0x0080
- #define Z_MASK 0x0040
- #define AD_MASK 0x0020
- #define CD_MASK 0x0010
- #define RCODE_MASK 0x000F
- #define DNS_RR_END (0XFFFF)
- #define UNUSED(expr) \
- do { \
- (void)(expr); \
- } while (0)
- #define member_size(type, member) sizeof(((type *)0)->member)
- static int is_aligned(void *ptr, int aligment)
- {
- return ((uintptr_t)(ptr)) % aligment == 0;
- }
- /* read short and move pointer */
- static unsigned short _dns_read_short(unsigned char **buffer)
- {
- unsigned short value = 0;
- if (is_aligned(*buffer, 2)) {
- value = *((unsigned short *)(*buffer));
- } else {
- memcpy(&value, *buffer, 2);
- }
- *buffer += 2;
- return ntohs(value);
- }
- /* write char and move pointer */
- static __attribute__((unused)) void _dns_write_char(unsigned char **buffer, unsigned char value)
- {
- **buffer = value;
- *buffer += 1;
- }
- /* read char and move pointer */
- static unsigned char _dns_read_char(unsigned char **buffer)
- {
- unsigned char value = **buffer;
- *buffer += 1;
- return value;
- }
- /* write short and move pointer */
- static void _dns_write_short(unsigned char **buffer, unsigned short value)
- {
- value = htons(value);
- if (is_aligned(*buffer, 2)) {
- *((unsigned short *)(*buffer)) = value;
- } else {
- memcpy(*buffer, &value, 2);
- }
- *buffer += 2;
- }
- /* write short and move pointer */
- static void _dns_write_shortptr(unsigned char **buffer, void *ptrvalue)
- {
- unsigned short value;
- if ((uintptr_t)ptrvalue % 2 == 0) {
- value = *(unsigned short *)ptrvalue;
- } else {
- memcpy(&value, ptrvalue, 2);
- }
- value = htons(value);
- if (is_aligned(*buffer, 2)) {
- *((unsigned short *)(*buffer)) = value;
- } else {
- memcpy(*buffer, &value, 2);
- }
- *buffer += 2;
- }
- /* write int and move pointer */
- static void _dns_write_int(unsigned char **buffer, unsigned int value)
- {
- value = htonl(value);
- if (is_aligned(*buffer, 4)) {
- *((unsigned int *)(*buffer)) = value;
- } else {
- memcpy(*buffer, &value, 4);
- }
- *buffer += 4;
- }
- /* write int and move pointer */
- static void _dns_write_intptr(unsigned char **buffer, void *ptrvalue)
- {
- unsigned int value;
- if ((uintptr_t)ptrvalue % 4 == 0) {
- value = *(unsigned int *)ptrvalue;
- } else {
- memcpy(&value, ptrvalue, 4);
- }
- value = htonl(value);
- if (is_aligned(*buffer, 4)) {
- *((unsigned int *)(*buffer)) = value;
- } else {
- memcpy(*buffer, &value, 4);
- }
- *buffer += 4;
- }
- /* read int and move pointer */
- static unsigned int _dns_read_int(unsigned char **buffer)
- {
- unsigned int value = 0;
- if (is_aligned(*buffer, 4)) {
- value = *((unsigned int *)(*buffer));
- } else {
- memcpy(&value, *buffer, 4);
- }
- *buffer += 4;
- return ntohl(value);
- }
- static inline int _dns_left_len(struct dns_context *context)
- {
- return context->maxsize - (context->ptr - context->data);
- }
- static int _dns_get_domain_from_packet(unsigned char *packet, int packet_size, unsigned char **domain_ptr, char *output,
- int size)
- {
- int output_len = 0;
- int copy_len = 0;
- int len = 0;
- unsigned char *ptr = *domain_ptr;
- int is_compressed = 0;
- int ptr_jump = 0;
- /*[len]string[len]string...[0]0 */
- while (1) {
- if (ptr >= packet + packet_size || ptr < packet || output_len >= size - 1 || ptr_jump > 32) {
- return -1;
- }
- len = *ptr;
- if (len == 0) {
- *output = 0;
- ptr++;
- break;
- }
- /* compressed domain */
- if (len >= 0xC0) {
- if ((ptr + 2) > (packet + packet_size)) {
- return -1;
- }
- /*
- 0 1 2 3 4 5 6 7 8 9 A B C D E F
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | 1 1| OFFSET |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- */
- /* read offset */
- len = _dns_read_short(&ptr) & 0x3FFF;
- if (is_compressed == 0) {
- *domain_ptr = ptr;
- }
- ptr = packet + len;
- if (ptr > packet + packet_size) {
- tlog(TLOG_DEBUG, "length is not enough %u:%ld, %p, %p", packet_size, (long)(ptr - packet), *domain_ptr,
- packet);
- return -1;
- }
- is_compressed = 1;
- ptr_jump++;
- continue;
- }
- ptr_jump = 0;
- /* change [len] to '.' */
- if (output_len > 0) {
- *output = '.';
- output++;
- output_len += 1;
- }
- if (ptr > packet + packet_size) {
- tlog(TLOG_DEBUG, "length is not enough %u:%ld, %p, %p", packet_size, (long)(ptr - packet), *domain_ptr,
- packet);
- return -1;
- }
- ptr++;
- if (output_len < size - 1) {
- /* copy sub string */
- copy_len = (len < size - output_len) ? len : size - 1 - output_len;
- if ((ptr + copy_len) > (packet + packet_size)) {
- tlog(TLOG_DEBUG, "length is not enough %u:%ld, %p, %p", packet_size, (long)(ptr - packet), *domain_ptr,
- packet);
- return -1;
- }
- memcpy(output, ptr, copy_len);
- }
- ptr += len;
- output += len;
- output_len += len;
- }
- if (is_compressed == 0) {
- *domain_ptr = ptr;
- }
- return 0;
- }
- static int _dns_decode_domain(struct dns_context *context, char *output, int size)
- {
- return _dns_get_domain_from_packet(context->data, context->maxsize, &(context->ptr), output, size);
- }
- static unsigned int dict_hash(const char *s)
- {
- unsigned int hashval = 0;
- for (hashval = 0; *s != '\0'; s++) {
- hashval = *s + 31 * hashval;
- }
- return hashval;
- }
- static int _dns_add_domain_dict(struct dns_context *context, unsigned int hash, int pos)
- {
- struct dns_packet_dict *dict = context->namedict;
- if (dict->dict_count >= DNS_PACKET_DICT_SIZE) {
- return -1;
- }
- if (hash == 0) {
- return -1;
- }
- if (pos >= context->maxsize) {
- return -1;
- }
- int index = dict->dict_count;
- dict->names[index].hash = hash;
- dict->names[index].pos = pos;
- dict->dict_count++;
- return 0;
- }
- static int _dns_get_domain_offset(struct dns_context *context, const char *domain)
- {
- int i = 0;
- char domain_check[DNS_MAX_CNAME_LEN];
- struct dns_packet_dict *dict = context->namedict;
- if (*domain == '\0') {
- return -1;
- }
- unsigned int hash = dict_hash(domain);
- for (i = 0; i < dict->dict_count; i++) {
- if (dict->names[i].hash != hash) {
- continue;
- }
- unsigned char *domain_check_ptr = dict->names[i].pos + context->data;
- if (_dns_get_domain_from_packet(context->data, context->maxsize, &domain_check_ptr, domain_check,
- DNS_MAX_CNAME_LEN) != 0) {
- return -1;
- }
- return dict->names[i].pos;
- }
- _dns_add_domain_dict(context, hash, context->ptr - 1 - context->data);
- return -1;
- }
- static int _dns_encode_domain(struct dns_context *context, const char *domain)
- {
- int num = 0;
- int total_len = 0;
- unsigned char *ptr_num = context->ptr++;
- int dict_offset = 0;
- dict_offset = _dns_get_domain_offset(context, domain);
- total_len++;
- /*[len]string[len]string...[0]0 */
- while (_dns_left_len(context) > 1 && *domain != 0) {
- total_len++;
- if (dict_offset >= 0) {
- int offset = 0xc000 | dict_offset;
- if (_dns_left_len(context) < 2) {
- return -1;
- }
- _dns_write_short(&ptr_num, offset);
- context->ptr++;
- ptr_num = NULL;
- return total_len;
- }
- if (*domain == '.') {
- *ptr_num = num;
- num = 0;
- ptr_num = context->ptr;
- domain++;
- context->ptr++;
- dict_offset = _dns_get_domain_offset(context, domain);
- continue;
- }
- *context->ptr = *domain;
- num++;
- context->ptr++;
- domain++;
- }
- if (_dns_left_len(context) < 1) {
- return -1;
- }
- *ptr_num = num;
- if (total_len > 1) {
- /* if domain is '\0', [domain] is '\0' */
- *(context->ptr) = 0;
- total_len++;
- context->ptr++;
- }
- if (_dns_left_len(context) <= 0) {
- return -1;
- }
- return total_len;
- }
- /* iterator get rrs begin */
- struct dns_rrs *dns_get_rrs_start(struct dns_packet *packet, dns_rr_type type, int *count)
- {
- unsigned short start = 0;
- struct dns_head *head = &packet->head;
- /* get rrs count by rrs type */
- switch (type) {
- case DNS_RRS_QD:
- *count = head->qdcount;
- start = packet->questions;
- break;
- case DNS_RRS_AN:
- *count = head->ancount;
- start = packet->answers;
- break;
- case DNS_RRS_NS:
- *count = head->nscount;
- start = packet->nameservers;
- break;
- case DNS_RRS_NR:
- *count = head->nrcount;
- start = packet->additional;
- break;
- case DNS_RRS_OPT:
- *count = packet->optcount;
- start = packet->optional;
- break;
- default:
- return NULL;
- break;
- }
- /* if not resource record, return null */
- if (start == DNS_RR_END) {
- return NULL;
- }
- /* return rrs data start address */
- return (struct dns_rrs *)(packet->data + start);
- }
- /* iterator next rrs */
- struct dns_rrs *dns_get_rrs_next(struct dns_packet *packet, struct dns_rrs *rrs)
- {
- if (rrs->next == DNS_RR_END) {
- return NULL;
- }
- return (struct dns_rrs *)(packet->data + rrs->next);
- }
- static void _dns_init_context_by_rrs(struct dns_rrs *rrs, struct dns_context *context)
- {
- context->packet = rrs->packet;
- context->data = rrs->packet->data;
- context->ptr = rrs->data;
- context->namedict = &rrs->packet->namedict;
- context->maxsize = rrs->data - rrs->packet->data + rrs->len;
- }
- /* iterator add rrs begin */
- static int _dns_add_rrs_start(struct dns_packet *packet, struct dns_context *context)
- {
- struct dns_rrs *rrs = NULL;
- unsigned char *end = packet->data + packet->len;
- if ((packet->len + (int)sizeof(*rrs)) >= packet->size) {
- return -1;
- }
- rrs = (struct dns_rrs *)end;
- context->ptr = rrs->data;
- context->packet = packet;
- context->maxsize = packet->size - sizeof(*packet);
- context->data = packet->data;
- context->namedict = &packet->namedict;
- return 0;
- }
- /* iterator add rrs end */
- static int _dns_rr_add_end(struct dns_packet *packet, int type, dns_type_t rtype, int len)
- {
- struct dns_rrs *rrs = NULL;
- struct dns_rrs *rrs_next = NULL;
- struct dns_head *head = &packet->head;
- unsigned char *end = packet->data + packet->len;
- unsigned short *count = NULL;
- unsigned short *start = NULL;
- rrs = (struct dns_rrs *)end;
- if (packet->len + len > packet->size - (int)sizeof(*packet) - (int)sizeof(*rrs)) {
- return -1;
- }
- switch (type) {
- case DNS_RRS_QD:
- count = &head->qdcount;
- start = &packet->questions;
- break;
- case DNS_RRS_AN:
- count = &head->ancount;
- start = &packet->answers;
- break;
- case DNS_RRS_NS:
- count = &head->nscount;
- start = &packet->nameservers;
- break;
- case DNS_RRS_NR:
- count = &head->nrcount;
- start = &packet->additional;
- break;
- case DNS_RRS_OPT:
- count = &packet->optcount;
- start = &packet->optional;
- break;
- default:
- return -1;
- break;
- }
- /* add data to end of dns_packet, and set previous rrs point to this rrs */
- if (*start != DNS_RR_END) {
- rrs_next = (struct dns_rrs *)(packet->data + *start);
- while (rrs_next->next != DNS_RR_END) {
- rrs_next = (struct dns_rrs *)(packet->data + rrs_next->next);
- }
- rrs_next->next = packet->len;
- } else {
- *start = packet->len;
- }
- /* update rrs head info */
- rrs->packet = packet;
- rrs->len = len;
- rrs->type = rtype;
- rrs->next = DNS_RR_END;
- /* update total data length */
- *count += 1;
- packet->len += len + sizeof(*rrs);
- return 0;
- }
- static int _dns_add_qr_head(struct dns_context *context, const char *domain, int qtype, int qclass)
- {
- int ret = _dns_encode_domain(context, domain);
- if (ret < 0) {
- return -1;
- }
- if (_dns_left_len(context) < 4) {
- return -1;
- }
- _dns_write_short(&context->ptr, qtype);
- _dns_write_short(&context->ptr, qclass);
- return ret + 4;
- }
- static int _dns_get_qr_head(struct dns_context *context, char *domain, int maxsize, int *qtype, int *qclass)
- {
- int ret = 0;
- if (domain == NULL || context == NULL) {
- return -1;
- }
- ret = _dns_decode_domain(context, domain, maxsize);
- if (ret < 0) {
- return -1;
- }
- if (_dns_left_len(context) < 4) {
- return -1;
- }
- *qtype = _dns_read_short(&context->ptr);
- *qclass = _dns_read_short(&context->ptr);
- return 0;
- }
- static int _dns_add_rr_head(struct dns_context *context, const char *domain, int qtype, int qclass, int ttl, int rr_len)
- {
- int len = 0;
- /* resource record head */
- /* |domain |
- * |qtype | qclass |
- * | ttl |
- * | rrlen | rrdata |
- */
- len = _dns_add_qr_head(context, domain, qtype, qclass);
- if (len < 0) {
- return -1;
- }
- if (_dns_left_len(context) < 6) {
- return -1;
- }
- _dns_write_int(&context->ptr, ttl);
- _dns_write_short(&context->ptr, rr_len);
- return len + 6;
- }
- static int _dns_get_rr_head(struct dns_context *context, char *domain, int maxsize, int *qtype, int *qclass, int *ttl,
- int *rr_len)
- {
- int len = 0;
- /* resource record head */
- /* |domain |
- * |qtype | qclass |
- * | ttl |
- * | rrlen | rrdata |
- */
- len = _dns_get_qr_head(context, domain, maxsize, qtype, qclass);
- if (_dns_left_len(context) < 6) {
- return -1;
- }
- *ttl = _dns_read_int(&context->ptr);
- *rr_len = _dns_read_short(&context->ptr);
- return len;
- }
- struct dns_rr_nested *dns_add_rr_nested_start(struct dns_rr_nested *rr_nested_buffer, struct dns_packet *packet,
- dns_rr_type type, dns_type_t rtype, const char *domain, int ttl)
- {
- int len = 0;
- memset(rr_nested_buffer, 0, sizeof(*rr_nested_buffer));
- rr_nested_buffer->type = type;
- int ret = 0;
- /* resource record */
- /* |domain |
- * |qtype | qclass |
- * | ttl |
- * | rrlen | rrdata |
- */
- ret = _dns_add_rrs_start(packet, &rr_nested_buffer->context);
- if (ret < 0) {
- return NULL;
- }
- rr_nested_buffer->rr_start = rr_nested_buffer->context.ptr;
- /* add rr head */
- len = _dns_add_rr_head(&rr_nested_buffer->context, domain, rtype, DNS_C_IN, ttl, 0);
- if (len < 0) {
- return NULL;
- }
- rr_nested_buffer->rr_len_ptr = rr_nested_buffer->context.ptr - 2;
- rr_nested_buffer->rr_head_len = len;
- return rr_nested_buffer;
- }
- int dns_add_rr_nested_memcpy(struct dns_rr_nested *rr_nested, const void *data, int data_len)
- {
- if (rr_nested == NULL || data == NULL || data_len <= 0) {
- return -1;
- }
- if (_dns_left_len(&rr_nested->context) < data_len) {
- return -1;
- }
- if (is_aligned(rr_nested->context.ptr, 2) == 0) {
- return -1;
- }
- memcpy(rr_nested->context.ptr, data, data_len);
- rr_nested->context.ptr += data_len;
- if (is_aligned(rr_nested->context.ptr, 2) == 0) {
- if (_dns_left_len(&rr_nested->context) < 1) {
- return -1;
- }
- _dns_write_char(&rr_nested->context.ptr, 0);
- }
- return 0;
- }
- int dns_add_rr_nested_end(struct dns_rr_nested *rr_nested, dns_type_t rtype)
- {
- if (rr_nested == NULL || rr_nested->rr_start == NULL) {
- return -1;
- }
- int len = rr_nested->context.ptr - rr_nested->rr_start;
- unsigned char *ptr = rr_nested->rr_len_ptr;
- if (ptr == NULL || _dns_left_len(&rr_nested->context) < 2) {
- return -1;
- }
- /* NO SVC keys, reset ptr */
- if (len <= 14) {
- rr_nested->context.ptr = rr_nested->rr_start;
- return 0;
- }
- _dns_write_short(&ptr, len - rr_nested->rr_head_len);
- return _dns_rr_add_end(rr_nested->context.packet, rr_nested->type, rtype, len);
- }
- void *dns_get_rr_nested_start(struct dns_rrs *rrs, char *domain, int maxsize, int *qtype, int *ttl, int *rr_len)
- {
- struct dns_context data_context;
- int qclass = 0;
- int ret = 0;
- _dns_init_context_by_rrs(rrs, &data_context);
- ret = _dns_get_rr_head(&data_context, domain, DNS_MAX_CNAME_LEN, qtype, &qclass, ttl, rr_len);
- if (ret < 0) {
- return NULL;
- }
- if (qclass != DNS_C_IN) {
- return NULL;
- }
- if (*rr_len < 2) {
- return NULL;
- }
- return data_context.ptr;
- }
- void *dns_get_rr_nested_next(struct dns_rrs *rrs, void *rr_nested, int rr_nested_len)
- {
- void *end = rrs->data + rrs->len;
- void *p = rr_nested + rr_nested_len;
- if (is_aligned(p, 2) == 0) {
- p++;
- }
- if (p == end) {
- return NULL;
- } else if (p > end) {
- return NULL;
- }
- return p;
- }
- static int _dns_add_RAW(struct dns_packet *packet, dns_rr_type rrtype, dns_type_t rtype, const char *domain, int ttl,
- const void *raw, int raw_len)
- {
- int len = 0;
- struct dns_context context;
- int ret = 0;
- if (raw_len < 0) {
- return -1;
- }
- /* resource record */
- /* |domain |
- * |qtype | qclass |
- * | ttl |
- * | rrlen | rrdata |
- */
- ret = _dns_add_rrs_start(packet, &context);
- if (ret < 0) {
- return -1;
- }
- /* add rr head */
- len = _dns_add_rr_head(&context, domain, rtype, DNS_C_IN, ttl, raw_len);
- if (len < 0) {
- return -1;
- }
- if (_dns_left_len(&context) < raw_len) {
- return -1;
- }
- /* add rr data */
- memcpy(context.ptr, raw, raw_len);
- context.ptr += raw_len;
- len += raw_len;
- return _dns_rr_add_end(packet, rrtype, rtype, len);
- }
- static int _dns_get_RAW(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, void *raw, int *raw_len)
- {
- int qtype = 0;
- int qclass = 0;
- int rr_len = 0;
- int ret = 0;
- struct dns_context context;
- /* resource record head */
- /* |domain |
- * |qtype | qclass |
- * | ttl |
- * | rrlen | rrdata |
- */
- _dns_init_context_by_rrs(rrs, &context);
- /* get rr head */
- ret = _dns_get_rr_head(&context, domain, maxsize, &qtype, &qclass, ttl, &rr_len);
- if (ret < 0) {
- return -1;
- }
- if (qtype != rrs->type || rr_len > *raw_len) {
- return -1;
- }
- /* get rr data */
- memcpy(raw, context.ptr, rr_len);
- context.ptr += rr_len;
- *raw_len = rr_len;
- return 0;
- }
- static int _dns_add_opt_RAW(struct dns_packet *packet, dns_opt_code_t opt_rrtype, void *raw, int raw_len)
- {
- unsigned char opt_data[DNS_MAX_OPT_LEN];
- struct dns_opt *opt = (struct dns_opt *)opt_data;
- int len = 0;
- opt->code = opt_rrtype;
- opt->length = sizeof(unsigned short);
- memcpy(opt->data, raw, raw_len);
- len += raw_len;
- len += sizeof(*opt);
- return _dns_add_RAW(packet, DNS_RRS_OPT, (dns_type_t)opt_rrtype, "", 0, opt_data, len);
- }
- static int _dns_get_opt_RAW(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, struct dns_opt *dns_opt,
- int *dns_optlen)
- {
- *dns_optlen = DNS_MAX_OPT_LEN;
- return _dns_get_RAW(rrs, domain, maxsize, ttl, dns_opt, dns_optlen);
- }
- static int __attribute__((unused)) _dns_add_OPT(struct dns_packet *packet, dns_rr_type type, unsigned short opt_code,
- unsigned short opt_len, struct dns_opt *opt)
- {
- int ret = 0;
- int len = 0;
- struct dns_context context;
- int total_len = sizeof(*opt) + opt->length;
- int ttl = 0;
- /*
- +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
- 0: | OPTION-CODE |
- +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
- 2: | OPTION-LENGTH |
- +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
- 4: | |
- / OPTION-DATA /
- / /
- +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
- */
- ret = _dns_add_rrs_start(packet, &context);
- if (ret < 0) {
- return -1;
- }
- if (_dns_left_len(&context) < total_len) {
- return -1;
- }
- ttl = (opt_code << 16) | opt_len;
- /* add rr head */
- len = _dns_add_rr_head(&context, "", type, DNS_C_IN, ttl, total_len);
- if (len < 0) {
- return -1;
- }
- /* add rr data */
- memcpy(context.ptr, opt, total_len);
- context.ptr += total_len;
- len = context.ptr - context.data - packet->len;
- return _dns_rr_add_end(packet, type, DNS_T_OPT, len);
- }
- static int __attribute__((unused)) _dns_get_OPT(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len,
- struct dns_opt *opt, int *opt_maxlen)
- {
- int qtype = 0;
- int qclass = 0;
- int rr_len = 0;
- int ret = 0;
- struct dns_context context;
- char domain[DNS_MAX_CNAME_LEN];
- int maxsize = DNS_MAX_CNAME_LEN;
- int ttl = 0;
- _dns_init_context_by_rrs(rrs, &context);
- /* get rr head */
- ret = _dns_get_rr_head(&context, domain, maxsize, &qtype, &qclass, &ttl, &rr_len);
- if (ret < 0) {
- return -1;
- }
- if (qtype != rrs->type || rr_len > *opt_len) {
- return -1;
- }
- /* get rr data */
- *opt_code = ttl >> 16;
- *opt_len = ttl & 0xFFFF;
- memcpy(opt, context.ptr, rr_len);
- context.ptr += rr_len;
- *opt_maxlen = rr_len;
- return 0;
- }
- int dns_add_CNAME(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, const char *cname)
- {
- int rr_len = strnlen(cname, DNS_MAX_CNAME_LEN) + 1;
- return _dns_add_RAW(packet, type, DNS_T_CNAME, domain, ttl, cname, rr_len);
- }
- int dns_get_CNAME(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size)
- {
- int len = cname_size;
- return _dns_get_RAW(rrs, domain, maxsize, ttl, cname, &len);
- }
- int dns_add_A(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl,
- unsigned char addr[DNS_RR_A_LEN])
- {
- return _dns_add_RAW(packet, type, DNS_T_A, domain, ttl, addr, DNS_RR_A_LEN);
- }
- int dns_get_A(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned char addr[DNS_RR_A_LEN])
- {
- int len = DNS_RR_A_LEN;
- return _dns_get_RAW(rrs, domain, maxsize, ttl, addr, &len);
- }
- int dns_add_PTR(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, const char *cname)
- {
- int rr_len = strnlen(cname, DNS_MAX_CNAME_LEN) + 1;
- return _dns_add_RAW(packet, type, DNS_T_PTR, domain, ttl, cname, rr_len);
- }
- int dns_get_PTR(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size)
- {
- int len = cname_size;
- return _dns_get_RAW(rrs, domain, maxsize, ttl, cname, &len);
- }
- int dns_add_TXT(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, const char *text)
- {
- int rr_len = strnlen(text, DNS_MAX_CNAME_LEN);
- char data[DNS_MAX_CNAME_LEN];
- if (rr_len > DNS_MAX_CNAME_LEN - 2) {
- return -1;
- }
- data[0] = rr_len;
- rr_len++;
- memcpy(data + 1, text, rr_len);
- data[rr_len] = 0;
- return _dns_add_RAW(packet, type, DNS_T_TXT, domain, ttl, data, rr_len);
- }
- int dns_get_TXT(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *text, int txt_size)
- {
- return -1;
- }
- int dns_add_NS(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, const char *cname)
- {
- int rr_len = strnlen(cname, DNS_MAX_CNAME_LEN) + 1;
- return _dns_add_RAW(packet, type, DNS_T_NS, domain, ttl, cname, rr_len);
- }
- int dns_get_NS(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size)
- {
- int len = cname_size;
- return _dns_get_RAW(rrs, domain, maxsize, ttl, cname, &len);
- }
- int dns_add_AAAA(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl,
- unsigned char addr[DNS_RR_AAAA_LEN])
- {
- return _dns_add_RAW(packet, type, DNS_T_AAAA, domain, ttl, addr, DNS_RR_AAAA_LEN);
- }
- int dns_get_AAAA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned char addr[DNS_RR_AAAA_LEN])
- {
- int len = DNS_RR_AAAA_LEN;
- return _dns_get_RAW(rrs, domain, maxsize, ttl, addr, &len);
- }
- int dns_add_SOA(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, struct dns_soa *soa)
- {
- /* SOA */
- /*| mname |
- *| rname |
- *| serial |
- *| refresh |
- *| retry |
- *| expire |
- *| minimum |
- */
- unsigned char data[sizeof(*soa)];
- unsigned char *ptr = data;
- int len = 0;
- if (soa == NULL || domain == NULL || packet == NULL) {
- return -1;
- }
- safe_strncpy((char *)ptr, soa->mname, DNS_MAX_CNAME_LEN);
- ptr += strnlen(soa->mname, DNS_MAX_CNAME_LEN - 1) + 1;
- safe_strncpy((char *)ptr, soa->rname, DNS_MAX_CNAME_LEN);
- ptr += strnlen(soa->rname, DNS_MAX_CNAME_LEN - 1) + 1;
- memcpy(ptr, &soa->serial, sizeof(unsigned int));
- ptr += 4;
- memcpy(ptr, &soa->refresh, sizeof(unsigned int));
- ptr += 4;
- memcpy(ptr, &soa->retry, sizeof(unsigned int));
- ptr += 4;
- memcpy(ptr, &soa->expire, sizeof(unsigned int));
- ptr += 4;
- memcpy(ptr, &soa->minimum, sizeof(unsigned int));
- ptr += 4;
- len = ptr - data;
- return _dns_add_RAW(packet, type, DNS_T_SOA, domain, ttl, data, len);
- }
- int dns_get_SOA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, struct dns_soa *soa)
- {
- unsigned char data[sizeof(*soa)];
- unsigned char *ptr = data;
- int len = sizeof(data);
- /* SOA */
- /*| mname |
- *| rname |
- *| serial |
- *| refresh |
- *| retry |
- *| expire |
- *| minimum |
- */
- if (_dns_get_RAW(rrs, domain, maxsize, ttl, data, &len) != 0) {
- return -1;
- }
- safe_strncpy(soa->mname, (char *)ptr, DNS_MAX_CNAME_LEN - 1);
- ptr += strnlen(soa->mname, DNS_MAX_CNAME_LEN - 1) + 1;
- if (ptr - data >= len) {
- return -1;
- }
- safe_strncpy(soa->rname, (char *)ptr, DNS_MAX_CNAME_LEN - 1);
- ptr += strnlen(soa->rname, DNS_MAX_CNAME_LEN - 1) + 1;
- if (ptr - data + 20 > len) {
- return -1;
- }
- memcpy(&soa->serial, ptr, 4);
- ptr += 4;
- memcpy(&soa->refresh, ptr, 4);
- ptr += 4;
- memcpy(&soa->retry, ptr, 4);
- ptr += 4;
- memcpy(&soa->expire, ptr, 4);
- ptr += 4;
- memcpy(&soa->minimum, ptr, 4);
- return 0;
- }
- int dns_set_OPT_payload_size(struct dns_packet *packet, int payload_size)
- {
- if (payload_size < 512) {
- payload_size = 512;
- }
- packet->payloadsize = payload_size;
- return 0;
- }
- int dns_get_OPT_payload_size(struct dns_packet *packet)
- {
- return packet->payloadsize;
- }
- int dns_set_OPT_option(struct dns_packet *packet, unsigned int option)
- {
- packet->opt_option = option;
- return 0;
- }
- unsigned int dns_get_OPT_option(struct dns_packet *packet)
- {
- return packet->opt_option;
- }
- int dns_add_OPT_ECS(struct dns_packet *packet, struct dns_opt_ecs *ecs)
- {
- unsigned char opt_data[DNS_MAX_OPT_LEN];
- struct dns_opt *opt = (struct dns_opt *)opt_data;
- int len = 0;
- /* ecs size 4 + bit of address*/
- len = 4;
- len += (ecs->source_prefix / 8);
- len += (ecs->source_prefix % 8 > 0) ? 1 : 0;
- opt->length = len;
- opt->code = DNS_OPT_T_ECS;
- memcpy(opt->data, ecs, len);
- len += sizeof(*opt);
- return _dns_add_RAW(packet, DNS_RRS_OPT, (dns_type_t)DNS_OPT_T_ECS, "", 0, opt_data, len);
- }
- int dns_get_OPT_ECS(struct dns_rrs *rrs, struct dns_opt_ecs *ecs)
- {
- unsigned char opt_data[DNS_MAX_OPT_LEN];
- char domain[DNS_MAX_CNAME_LEN] = {0};
- struct dns_opt *opt = (struct dns_opt *)opt_data;
- int len = DNS_MAX_OPT_LEN;
- int ttl = 0;
- if (_dns_get_RAW(rrs, domain, DNS_MAX_CNAME_LEN, &ttl, opt_data, &len) != 0) {
- return -1;
- }
- if (len < (int)sizeof(*opt)) {
- return -1;
- }
- if (opt->code != DNS_OPT_T_ECS) {
- return -1;
- }
- memcpy(ecs, opt->data, opt->length);
- return 0;
- }
- int dns_add_OPT_TCP_KEEPALIVE(struct dns_packet *packet, unsigned short timeout)
- {
- unsigned short timeout_net = htons(timeout);
- int data_len = 0;
- if (timeout > 0) {
- data_len = sizeof(timeout);
- }
- return _dns_add_opt_RAW(packet, DNS_OPT_T_TCP_KEEPALIVE, &timeout_net, data_len);
- }
- int dns_get_OPT_TCP_KEEPALIVE(struct dns_rrs *rrs, unsigned short *timeout)
- {
- unsigned char opt_data[DNS_MAX_OPT_LEN];
- char domain[DNS_MAX_CNAME_LEN] = {0};
- struct dns_opt *opt = (struct dns_opt *)opt_data;
- int len = DNS_MAX_OPT_LEN;
- int ttl = 0;
- unsigned char *data = NULL;
- if (_dns_get_opt_RAW(rrs, domain, DNS_MAX_CNAME_LEN, &ttl, opt, &len) != 0) {
- return -1;
- }
- if (len < (int)sizeof(*opt)) {
- return -1;
- }
- if (opt->code != DNS_OPT_T_TCP_KEEPALIVE) {
- return -1;
- }
- if (opt->length == 0) {
- *timeout = 0;
- return 0;
- }
- if (opt->length != sizeof(unsigned short)) {
- return -1;
- }
- data = opt->data;
- *timeout = _dns_read_short(&data);
- return 0;
- }
- int dns_add_SRV(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, int priority, int weight,
- int port, const char *target)
- {
- unsigned char data[DNS_MAX_CNAME_LEN];
- unsigned char *data_ptr = data;
- int target_len = 0;
- if (target == NULL) {
- target = "";
- }
- target_len = strnlen(target, DNS_MAX_CNAME_LEN) + 1;
- memcpy(data_ptr, &priority, sizeof(unsigned short));
- data_ptr += sizeof(unsigned short);
- memcpy(data_ptr, &weight, sizeof(unsigned short));
- data_ptr += sizeof(unsigned short);
- memcpy(data_ptr, &port, sizeof(unsigned short));
- data_ptr += sizeof(unsigned short);
- if (data_ptr - data + target_len >= DNS_MAX_CNAME_LEN) {
- return -1;
- }
- safe_strncpy((char *)data_ptr, target, target_len);
- data_ptr += target_len;
- return _dns_add_RAW(packet, type, DNS_T_SRV, domain, ttl, data, data_ptr - data);
- }
- int dns_get_SRV(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned short *priority,
- unsigned short *weight, unsigned short *port, char *target, int target_size)
- {
- unsigned char data[DNS_MAX_CNAME_LEN];
- unsigned char *ptr = data;
- int len = sizeof(data);
- if (_dns_get_RAW(rrs, domain, maxsize, ttl, data, &len) != 0) {
- return -1;
- }
- if (len < 6) {
- return -1;
- }
- memcpy(priority, ptr, sizeof(unsigned short));
- ptr += sizeof(unsigned short);
- memcpy(weight, ptr, sizeof(unsigned short));
- ptr += sizeof(unsigned short);
- memcpy(port, ptr, sizeof(unsigned short));
- ptr += sizeof(unsigned short);
- safe_strncpy(target, (char *)ptr, target_size);
- return 0;
- }
- int dns_add_HTTPS_start(struct dns_rr_nested *svcparam_buffer, struct dns_packet *packet, dns_rr_type type,
- const char *domain, int ttl, int priority, const char *target)
- {
- svcparam_buffer = dns_add_rr_nested_start(svcparam_buffer, packet, type, DNS_T_HTTPS, domain, ttl);
- if (svcparam_buffer == NULL) {
- return -1;
- }
- int target_len = 0;
- if (target == NULL) {
- target = "";
- }
- target_len = strnlen(target, DNS_MAX_CNAME_LEN) + 1;
- if (_dns_left_len(&svcparam_buffer->context) < 2 + target_len) {
- return -1;
- }
- /* add rr data */
- _dns_write_short(&svcparam_buffer->context.ptr, priority);
- safe_strncpy((char *)svcparam_buffer->context.ptr, target, target_len);
- svcparam_buffer->context.ptr += target_len;
- if (is_aligned(svcparam_buffer->context.ptr, 2) != 1) {
- if (_dns_left_len(&svcparam_buffer->context) < 1) {
- return -1;
- }
- _dns_write_char(&svcparam_buffer->context.ptr, 0);
- }
- return 0;
- }
- int dns_HTTPS_add_raw(struct dns_rr_nested *svcparam, unsigned short key, unsigned char *value, unsigned short len)
- {
- if (_dns_left_len(&svcparam->context) < 2 + len) {
- return -1;
- }
- if (dns_add_rr_nested_memcpy(svcparam, &key, 2) != 0) {
- return -1;
- }
- if (dns_add_rr_nested_memcpy(svcparam, &len, 2) != 0) {
- return -1;
- }
- if (dns_add_rr_nested_memcpy(svcparam, value, len) != 0) {
- return -1;
- }
- return 0;
- }
- int dns_HTTPS_add_port(struct dns_rr_nested *svcparam, unsigned short port)
- {
- if (_dns_left_len(&svcparam->context) < 6) {
- return -1;
- }
- unsigned short value = DNS_HTTPS_T_PORT;
- if (dns_add_rr_nested_memcpy(svcparam, &value, 2) != 0) {
- return -1;
- }
- value = 2;
- if (dns_add_rr_nested_memcpy(svcparam, &value, 2) != 0) {
- return -1;
- }
- value = htons(port);
- if (dns_add_rr_nested_memcpy(svcparam, &value, 2) != 0) {
- return -1;
- }
- return 0;
- }
- int dns_HTTPS_add_alpn(struct dns_rr_nested *svcparam, const char *alpn, int alpn_len)
- {
- if (_dns_left_len(&svcparam->context) < 2 + 2 + alpn_len) {
- return -1;
- }
- unsigned short value = DNS_HTTPS_T_ALPN;
- if (dns_add_rr_nested_memcpy(svcparam, &value, 2) != 0) {
- return -1;
- }
- value = alpn_len;
- if (dns_add_rr_nested_memcpy(svcparam, &value, 2) != 0) {
- return -1;
- }
- if (dns_add_rr_nested_memcpy(svcparam, alpn, alpn_len) != 0) {
- return -1;
- }
- return 0;
- }
- int dns_HTTPS_add_ech(struct dns_rr_nested *svcparam, void *ech, int ech_len)
- {
- if (_dns_left_len(&svcparam->context) < 2 + 2 + ech_len) {
- return -1;
- }
- unsigned short value = DNS_HTTPS_T_ECH;
- if (dns_add_rr_nested_memcpy(svcparam, &value, 2) != 0) {
- return -1;
- }
- value = ech_len;
- if (dns_add_rr_nested_memcpy(svcparam, &value, 2) != 0) {
- return -1;
- }
- if (dns_add_rr_nested_memcpy(svcparam, ech, ech_len) != 0) {
- return -1;
- }
- return 0;
- }
- int dns_HTTPS_add_ipv4hint(struct dns_rr_nested *svcparam, unsigned char *addr[], int addr_num)
- {
- if (_dns_left_len(&svcparam->context) < 4 + addr_num * DNS_RR_A_LEN) {
- return -1;
- }
- unsigned short value = DNS_HTTPS_T_IPV4HINT;
- if (dns_add_rr_nested_memcpy(svcparam, &value, 2) != 0) {
- return -1;
- }
- value = addr_num * DNS_RR_A_LEN;
- if (dns_add_rr_nested_memcpy(svcparam, &value, 2) != 0) {
- return -1;
- }
- for (int i = 0; i < addr_num; i++) {
- if (dns_add_rr_nested_memcpy(svcparam, addr[i], DNS_RR_A_LEN) != 0) {
- return -1;
- }
- }
- return 0;
- }
- int dns_HTTPS_add_ipv6hint(struct dns_rr_nested *svcparam, unsigned char *addr[], int addr_num)
- {
- if (_dns_left_len(&svcparam->context) < 4 + addr_num * DNS_RR_AAAA_LEN) {
- return -1;
- }
- unsigned short value = DNS_HTTPS_T_IPV6HINT;
- if (dns_add_rr_nested_memcpy(svcparam, &value, 2) != 0) {
- return -1;
- }
- value = addr_num * DNS_RR_AAAA_LEN;
- if (dns_add_rr_nested_memcpy(svcparam, &value, 2) != 0) {
- return -1;
- }
- for (int i = 0; i < addr_num; i++) {
- if (dns_add_rr_nested_memcpy(svcparam, addr[i], DNS_RR_AAAA_LEN) != 0) {
- return -1;
- }
- }
- return 0;
- }
- int dns_add_HTTPS_end(struct dns_rr_nested *svcparam)
- {
- return dns_add_rr_nested_end(svcparam, DNS_T_HTTPS);
- }
- int dns_get_HTTPS_svcparm_start(struct dns_rrs *rrs, struct dns_https_param **https_param, char *domain, int maxsize,
- int *ttl, int *priority, char *target, int target_size)
- {
- int qtype = 0;
- unsigned char *data = NULL;
- int rr_len = 0;
- data = dns_get_rr_nested_start(rrs, domain, maxsize, &qtype, ttl, &rr_len);
- if (data == NULL) {
- return -1;
- }
- if (qtype != DNS_T_HTTPS) {
- return -1;
- }
- if (rr_len < 2) {
- return -1;
- }
- *priority = _dns_read_short(&data);
- rr_len -= 2;
- if (rr_len <= 0) {
- return -1;
- }
- int len = strnlen((char *)data, rr_len);
- safe_strncpy(target, (char *)data, target_size);
- data += len + 1;
- rr_len -= len + 1;
- if (rr_len < 0) {
- return -1;
- }
- /* PADDING */
- if (is_aligned(data, 2) != 1) {
- data++;
- rr_len--;
- }
- if (rr_len == 0) {
- *https_param = NULL;
- return 0;
- }
- *https_param = (struct dns_https_param *)data;
- return 0;
- }
- struct dns_https_param *dns_get_HTTPS_svcparm_next(struct dns_rrs *rrs, struct dns_https_param *param)
- {
- return dns_get_rr_nested_next(rrs, param, sizeof(struct dns_https_param) + param->len);
- }
- /*
- * Format:
- * |DNS_NAME\0(string)|qtype(short)|qclass(short)|
- */
- int dns_add_domain(struct dns_packet *packet, const char *domain, int qtype, int qclass)
- {
- int len = 0;
- int ret = 0;
- struct dns_context context;
- ret = _dns_add_rrs_start(packet, &context);
- if (ret < 0) {
- return -1;
- }
- len = _dns_add_qr_head(&context, domain, qtype, qclass);
- if (len < 0) {
- return -1;
- }
- return _dns_rr_add_end(packet, DNS_RRS_QD, DNS_T_CNAME, len);
- }
- int dns_get_domain(struct dns_rrs *rrs, char *domain, int maxsize, int *qtype, int *qclass)
- {
- struct dns_context context;
- _dns_init_context_by_rrs(rrs, &context);
- return _dns_get_qr_head(&context, domain, maxsize, qtype, qclass);
- }
- static int _dns_decode_head(struct dns_context *context)
- {
- unsigned int fields = 0;
- int len = 12;
- struct dns_head *head = &context->packet->head;
- if (_dns_left_len(context) < len) {
- return -1;
- }
- /*
- 0 1 2 3 4 5 6 7 8 9 A B C D E F
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | ID |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | QDCOUNT |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | ANCOUNT |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | NSCOUNT |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | ARCOUNT |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- */
- head->id = _dns_read_short(&context->ptr);
- fields = _dns_read_short(&context->ptr);
- head->qr = (fields & QR_MASK) >> 15;
- head->opcode = (fields & OPCODE_MASK) >> 11;
- head->aa = (fields & AA_MASK) >> 10;
- head->tc = (fields & TC_MASK) >> 9;
- head->rd = (fields & RD_MASK) >> 8;
- head->ra = (fields & RA_MASK) >> 7;
- head->z = (fields & Z_MASK) >> 6;
- head->ad = (fields & AD_MASK) >> 5;
- head->cd = (fields & CD_MASK) >> 4;
- head->rcode = (fields & RCODE_MASK) >> 0;
- head->qdcount = _dns_read_short(&context->ptr);
- head->ancount = _dns_read_short(&context->ptr);
- head->nscount = _dns_read_short(&context->ptr);
- head->nrcount = _dns_read_short(&context->ptr);
- return 0;
- }
- static int _dns_encode_head(struct dns_context *context)
- {
- int len = 12;
- struct dns_head *head = &context->packet->head;
- if (_dns_left_len(context) < len) {
- return -1;
- }
- _dns_write_short(&context->ptr, head->id);
- int fields = 0;
- fields |= (head->qr << 15) & QR_MASK;
- fields |= (head->opcode << 11) & OPCODE_MASK;
- fields |= (head->aa << 10) & AA_MASK;
- fields |= (head->tc << 9) & TC_MASK;
- fields |= (head->rd << 8) & RD_MASK;
- fields |= (head->ra << 7) & RA_MASK;
- fields |= (head->z << 6) & Z_MASK;
- fields |= (head->ad << 5) & AD_MASK;
- fields |= (head->cd << 4) & CD_MASK;
- fields |= (head->rcode << 0) & RCODE_MASK;
- _dns_write_short(&context->ptr, fields);
- _dns_write_short(&context->ptr, head->qdcount);
- _dns_write_short(&context->ptr, head->ancount);
- _dns_write_short(&context->ptr, head->nscount);
- _dns_write_short(&context->ptr, head->nrcount);
- return len;
- }
- static int _dns_encode_head_count(struct dns_context *context)
- {
- int len = 12;
- struct dns_head *head = &context->packet->head;
- unsigned char *ptr = context->data;
- ptr += 4;
- _dns_write_short(&ptr, head->qdcount);
- _dns_write_short(&ptr, head->ancount);
- _dns_write_short(&ptr, head->nscount);
- _dns_write_short(&ptr, head->nrcount);
- return len;
- }
- static int _dns_decode_qr_head(struct dns_context *context, char *domain, int domain_size, int *qtype, int *qclass)
- {
- int ret = 0;
- /*
- 0 1 2 3 4 5 6 7 8 9 A B C D E F
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | |
- / /
- / NAME /
- | |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | TYPE |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | CLASS |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- */
- ret = _dns_decode_domain(context, domain, domain_size);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode domain failed.");
- return -1;
- }
- if (_dns_left_len(context) < 4) {
- tlog(TLOG_DEBUG, "left length is not enough, %s.", domain);
- return -1;
- }
- *qtype = _dns_read_short(&context->ptr);
- *qclass = _dns_read_short(&context->ptr);
- return 0;
- }
- static int _dns_encode_qr_head(struct dns_context *context, char *domain, int qtype, int qclass)
- {
- int ret = 0;
- ret = _dns_encode_domain(context, domain);
- if (ret < 0) {
- return -1;
- }
- if (_dns_left_len(context) < 4) {
- return -1;
- }
- _dns_write_short(&context->ptr, qtype);
- _dns_write_short(&context->ptr, qclass);
- return 0;
- }
- static int _dns_decode_rr_head(struct dns_context *context, char *domain, int domain_size, int *qtype, int *qclass,
- int *ttl, int *rr_len)
- {
- int len = 0;
- len = _dns_decode_qr_head(context, domain, domain_size, qtype, qclass);
- if (len < 0) {
- tlog(TLOG_DEBUG, "decode qr head failed.");
- return -1;
- }
- if (_dns_left_len(context) < 6) {
- tlog(TLOG_DEBUG, "left length is not enough.");
- return -1;
- }
- *ttl = _dns_read_int(&context->ptr);
- *rr_len = _dns_read_short(&context->ptr);
- if (*rr_len < 0 || *ttl < 0) {
- tlog(TLOG_DEBUG, "rr len or ttl is invalid.");
- return -1;
- }
- return 0;
- }
- static int _dns_encode_rr_head(struct dns_context *context, char *domain, int qtype, int qclass, int ttl, int rr_len,
- unsigned char **rr_len_ptr)
- {
- int ret = 0;
- ret = _dns_encode_qr_head(context, domain, qtype, qclass);
- if (ret < 0) {
- return -1;
- }
- if (_dns_left_len(context) < 6) {
- return -1;
- }
- _dns_write_int(&context->ptr, ttl);
- if (rr_len_ptr) {
- *rr_len_ptr = context->ptr;
- }
- _dns_write_short(&context->ptr, rr_len);
- return 0;
- }
- static int _dns_encode_raw(struct dns_context *context, struct dns_rrs *rrs)
- {
- int ret = 0;
- int qtype = 0;
- int qclass = 0;
- int ttl = 0;
- char domain[DNS_MAX_CNAME_LEN];
- int rr_len = 0;
- unsigned char *rr_len_ptr = NULL;
- struct dns_context data_context;
- /*
- 0 1 2 3 4 5 6 7 8 9 A B C D E F
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | |
- / /
- / NAME /
- | |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | TYPE |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | CLASS |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | TTL |
- | |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | RDLENGTH |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
- / RDATA /
- / /
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- */
- _dns_init_context_by_rrs(rrs, &data_context);
- ret = _dns_get_rr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len);
- if (ret < 0) {
- return -1;
- }
- ret = _dns_encode_rr_head(context, domain, qtype, qclass, ttl, rr_len, &rr_len_ptr);
- if (ret < 0) {
- return -1;
- }
- if (_dns_left_len(context) < rr_len) {
- return -1;
- }
- memcpy(context->ptr, data_context.ptr, rr_len);
- context->ptr += rr_len;
- data_context.ptr += rr_len;
- return 0;
- }
- static int _dns_decode_raw(struct dns_context *context, unsigned char *raw, int len)
- {
- if (_dns_left_len(context) < len || len < 0) {
- return -1;
- }
- memcpy(raw, context->ptr, len);
- context->ptr += len;
- return 0;
- }
- static int _dns_decode_CNAME(struct dns_context *context, char *cname, int cname_size)
- {
- int ret = 0;
- ret = _dns_decode_domain(context, cname, cname_size);
- if (ret < 0) {
- return -1;
- }
- return 0;
- }
- static int _dns_encode_CNAME(struct dns_context *context, struct dns_rrs *rrs)
- {
- int ret = 0;
- int qtype = 0;
- int qclass = 0;
- int ttl = 0;
- char domain[DNS_MAX_CNAME_LEN];
- int rr_len = 0;
- unsigned char *rr_len_ptr = NULL;
- struct dns_context data_context;
- _dns_init_context_by_rrs(rrs, &data_context);
- ret = _dns_get_rr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len);
- if (ret < 0) {
- return -1;
- }
- /* when code domain, len must plus 1, because of length at the beginning */
- rr_len = 1;
- ret = _dns_encode_rr_head(context, domain, qtype, qclass, ttl, rr_len, &rr_len_ptr);
- if (ret < 0) {
- return -1;
- }
- ret = _dns_encode_domain(context, (char *)data_context.ptr);
- if (ret < 0) {
- return -1;
- }
- rr_len += ret;
- data_context.ptr += strnlen((char *)(data_context.ptr), DNS_MAX_CNAME_LEN) + 1;
- if (rr_len > rrs->len) {
- return -1;
- }
- _dns_write_short(&rr_len_ptr, ret);
- return 0;
- }
- static int _dns_decode_SRV(struct dns_context *context, unsigned short *priority, unsigned short *weight,
- unsigned short *port, char *target, int target_size)
- {
- int ret = 0;
- if (_dns_left_len(context) < 6) {
- return -1;
- }
- *priority = _dns_read_short(&context->ptr);
- *weight = _dns_read_short(&context->ptr);
- *port = _dns_read_short(&context->ptr);
- ret = _dns_decode_domain(context, target, target_size);
- if (ret < 0) {
- return -1;
- }
- return 0;
- }
- static int _dns_decode_SOA(struct dns_context *context, struct dns_soa *soa)
- {
- int ret = 0;
- ret = _dns_decode_domain(context, soa->mname, DNS_MAX_CNAME_LEN - 1);
- if (ret < 0) {
- return -1;
- }
- ret = _dns_decode_domain(context, soa->rname, DNS_MAX_CNAME_LEN - 1);
- if (ret < 0) {
- return -1;
- }
- if (_dns_left_len(context) < 20) {
- return -1;
- }
- soa->serial = _dns_read_int(&context->ptr);
- soa->refresh = _dns_read_int(&context->ptr);
- soa->retry = _dns_read_int(&context->ptr);
- soa->expire = _dns_read_int(&context->ptr);
- soa->minimum = _dns_read_int(&context->ptr);
- return 0;
- }
- static int _dns_encode_SOA(struct dns_context *context, struct dns_rrs *rrs)
- {
- int ret = 0;
- int qtype = 0;
- int qclass = 0;
- int ttl = 0;
- char domain[DNS_MAX_CNAME_LEN];
- int rr_len = 0;
- unsigned char *rr_len_ptr = NULL;
- struct dns_context data_context;
- _dns_init_context_by_rrs(rrs, &data_context);
- ret = _dns_get_rr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len);
- if (ret < 0) {
- return -1;
- }
- ret = _dns_encode_rr_head(context, domain, qtype, qclass, ttl, rr_len, &rr_len_ptr);
- if (ret < 0) {
- return -1;
- }
- rr_len = 0;
- /* mname */
- ret = _dns_encode_domain(context, (char *)data_context.ptr);
- if (ret < 0) {
- return -1;
- }
- rr_len += ret;
- data_context.ptr += strnlen((char *)(data_context.ptr), DNS_MAX_CNAME_LEN) + 1;
- /* rname */
- ret = _dns_encode_domain(context, (char *)data_context.ptr);
- if (ret < 0) {
- return -1;
- }
- rr_len += ret;
- data_context.ptr += strnlen((char *)(data_context.ptr), DNS_MAX_CNAME_LEN) + 1;
- if (rr_len > rrs->len) {
- return -1;
- }
- rr_len += 20;
- _dns_write_short(&rr_len_ptr, rr_len);
- if (_dns_left_len(context) < 20) {
- return -1;
- }
- _dns_write_intptr(&context->ptr, data_context.ptr);
- data_context.ptr += 4;
- _dns_write_intptr(&context->ptr, data_context.ptr);
- data_context.ptr += 4;
- _dns_write_intptr(&context->ptr, data_context.ptr);
- data_context.ptr += 4;
- _dns_write_intptr(&context->ptr, data_context.ptr);
- data_context.ptr += 4;
- _dns_write_intptr(&context->ptr, data_context.ptr);
- data_context.ptr += 4;
- return 0;
- }
- static int _dns_encode_SRV(struct dns_context *context, struct dns_rrs *rrs)
- {
- int ret = 0;
- int qtype = 0;
- int qclass = 0;
- int ttl = 0;
- char domain[DNS_MAX_CNAME_LEN];
- int rr_len = 0;
- unsigned char *rr_len_ptr = NULL;
- struct dns_context data_context;
- _dns_init_context_by_rrs(rrs, &data_context);
- ret = _dns_get_rr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len);
- if (ret < 0) {
- return -1;
- }
- ret = _dns_encode_rr_head(context, domain, qtype, qclass, ttl, rr_len, &rr_len_ptr);
- if (ret < 0) {
- return -1;
- }
- rr_len = 0;
- if (_dns_left_len(context) < 6) {
- return -1;
- }
- _dns_write_shortptr(&context->ptr, data_context.ptr);
- data_context.ptr += 2;
- _dns_write_shortptr(&context->ptr, data_context.ptr);
- data_context.ptr += 2;
- _dns_write_shortptr(&context->ptr, data_context.ptr);
- data_context.ptr += 2;
- rr_len += 6;
- ret = _dns_encode_domain(context, (char *)data_context.ptr);
- if (ret < 0) {
- return -1;
- }
- rr_len += ret;
- data_context.ptr += strnlen((char *)(data_context.ptr), DNS_MAX_CNAME_LEN) + 1;
- _dns_write_short(&rr_len_ptr, rr_len);
- return 0;
- }
- static int _dns_decode_opt_ecs(struct dns_context *context, struct dns_opt_ecs *ecs, int opt_len)
- {
- int len = 0;
- if (opt_len < 4) {
- return -1;
- }
- ecs->family = _dns_read_short(&context->ptr);
- ecs->source_prefix = _dns_read_char(&context->ptr);
- ecs->scope_prefix = _dns_read_char(&context->ptr);
- len = (ecs->source_prefix / 8);
- len += (ecs->source_prefix % 8 > 0) ? 1 : 0;
- if (_dns_left_len(context) < len || len > (int)sizeof(ecs->addr)) {
- return -1;
- }
- memcpy(ecs->addr, context->ptr, len);
- context->ptr += len;
- tlog(TLOG_DEBUG, "ECS: family:%d, source_prefix:%d, scope_prefix:%d, len:%d", ecs->family, ecs->source_prefix,
- ecs->scope_prefix, len);
- tlog(TLOG_DEBUG, "%d.%d.%d.%d", ecs->addr[0], ecs->addr[1], ecs->addr[2], ecs->addr[3]);
- return 0;
- }
- static int _dns_decode_opt_cookie(struct dns_context *context, struct dns_opt_cookie *cookie, int opt_len)
- {
- if (opt_len < (int)member_size(struct dns_opt_cookie, client_cookie)) {
- return -1;
- }
- int len = 8;
- memcpy(cookie->client_cookie, context->ptr, len);
- context->ptr += len;
- opt_len -= len;
- if (opt_len <= 0) {
- cookie->server_cookie_len = 0;
- return 0;
- }
- if (opt_len < 8 || opt_len > (int)member_size(struct dns_opt_cookie, server_cookie)) {
- return -1;
- }
- memcpy(cookie->server_cookie, context->ptr, opt_len);
- cookie->server_cookie_len = opt_len;
- context->ptr += opt_len;
- tlog(TLOG_DEBUG, "OPT COOKIE");
- return 0;
- }
- static int _dns_decode_opt_tcp_keepalive(struct dns_context *context, unsigned short *timeout, int opt_len)
- {
- if (opt_len == 0) {
- *timeout = 0;
- return 0;
- }
- if (opt_len < (int)sizeof(unsigned short)) {
- return -1;
- }
- *timeout = _dns_read_short(&context->ptr);
- tlog(TLOG_DEBUG, "OPT TCP KEEPALIVE %u", *timeout);
- return 0;
- }
- static int _dns_encode_OPT(struct dns_context *context, struct dns_rrs *rrs)
- {
- int ret = 0;
- int opt_code = 0;
- int qclass = 0;
- char domain[DNS_MAX_CNAME_LEN];
- struct dns_context data_context;
- int rr_len = 0;
- int ttl = 0;
- struct dns_opt *dns_opt = NULL;
- _dns_init_context_by_rrs(rrs, &data_context);
- ret = _dns_get_rr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &opt_code, &qclass, &ttl, &rr_len);
- if (ret < 0) {
- return -1;
- }
- if (rr_len < (int)sizeof(*dns_opt)) {
- return -1;
- }
- if (_dns_left_len(context) < (rr_len)) {
- return -1;
- }
- dns_opt = (struct dns_opt *)data_context.ptr;
- _dns_write_short(&context->ptr, dns_opt->code);
- _dns_write_short(&context->ptr, dns_opt->length);
- if (_dns_left_len(context) < dns_opt->length) {
- return -1;
- }
- switch (dns_opt->code) {
- case DNS_OPT_T_ECS: {
- struct dns_opt_ecs *ecs = (struct dns_opt_ecs *)&(dns_opt->data);
- _dns_write_short(&context->ptr, ecs->family);
- _dns_write_char(&context->ptr, ecs->source_prefix);
- _dns_write_char(&context->ptr, ecs->scope_prefix);
- memcpy(context->ptr, ecs->addr, dns_opt->length - 4);
- context->ptr += dns_opt->length - 4;
- } break;
- default:
- memcpy(context->ptr, dns_opt->data, dns_opt->length);
- context->ptr += dns_opt->length;
- break;
- }
- return 0;
- }
- static int _dns_get_opts_data_len(struct dns_packet *packet, struct dns_rrs *rrs, int count)
- {
- int i = 0;
- int len = 0;
- int opt_code = 0;
- int qclass = 0;
- int ttl = 0;
- int ret = 0;
- char domain[DNS_MAX_CNAME_LEN];
- struct dns_context data_context;
- int rr_len = 0;
- for (i = 0; i < count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
- _dns_init_context_by_rrs(rrs, &data_context);
- ret = _dns_get_rr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &opt_code, &qclass, &ttl, &rr_len);
- if (ret < 0) {
- return -1;
- }
- len += rr_len;
- }
- return len;
- }
- static int _dns_encode_opts(struct dns_packet *packet, struct dns_context *context, struct dns_rrs *rrs, int count)
- {
- int i = 0;
- int len = 0;
- int ret = 0;
- unsigned int rcode = packet->opt_option;
- int rr_len = 0;
- int payloadsize = packet->payloadsize;
- unsigned char *rr_len_ptr = NULL;
- rr_len = _dns_get_opts_data_len(packet, rrs, count);
- if (rr_len < 0) {
- return -1;
- }
- if (payloadsize < DNS_DEFAULT_PACKET_SIZE) {
- payloadsize = DNS_DEFAULT_PACKET_SIZE;
- }
- ret = _dns_encode_rr_head(context, "", DNS_T_OPT, payloadsize, rcode, rr_len, &rr_len_ptr);
- if (ret < 0) {
- return -1;
- }
- if (_dns_left_len(context) < rr_len) {
- return -1;
- }
- for (i = 0; i < count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
- len = _dns_encode_OPT(context, rrs);
- if (len < 0) {
- return -1;
- }
- }
- return 0;
- }
- static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsigned int ttl, int rr_len)
- {
- unsigned short opt_code = 0;
- unsigned short opt_len = 0;
- unsigned short errcode = (ttl >> 16) & 0xFFFF;
- unsigned short ever = (ttl) & 0xFFFF;
- unsigned char *start = context->ptr;
- struct dns_packet *packet = context->packet;
- int ret = 0;
- UNUSED(ever);
- /*
- Field Name Field Type Description
- ------------------------------------------------------
- NAME domain name empty (root domain)
- TYPE u_int16_t OPT
- CLASS u_int16_t sender's UDP payload size
- TTL u_int32_t extended RCODE and flags
- RDLEN u_int16_t describes RDATA
- RDATA octet stream {attribute,value} pairs
- +0 (MSB) +1 (LSB)
- +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
- 0: | OPTION-CODE |
- +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
- 2: | OPTION-LENGTH |
- +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
- 4: | |
- / OPTION-DATA /
- / /
- +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
- TTL
- +0 (MSB) +1 (LSB)
- +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
- 0: | EXTENDED-RCODE | VERSION |
- +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
- 2: | Z |
- +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
- */
- if (rr_len < 0) {
- tlog(TLOG_DEBUG, "opt len is invalid.");
- return -1;
- }
- if (errcode != 0) {
- tlog(TLOG_DEBUG, "extend rcode invalid, %d", errcode);
- return 0;
- }
- while (context->ptr - start < rr_len) {
- if (_dns_left_len(context) < 4) {
- tlog(TLOG_DEBUG, "data length is invalid, %d:%d", _dns_left_len(context),
- (int)(context->ptr - context->data));
- return -1;
- }
- opt_code = _dns_read_short(&context->ptr);
- opt_len = _dns_read_short(&context->ptr);
- if (_dns_left_len(context) < opt_len) {
- tlog(TLOG_DEBUG, "read opt data failed, opt_code = %d, opt_len = %d", opt_code, opt_len);
- return -1;
- }
- tlog(TLOG_DEBUG, "opt type %d", opt_code);
- switch (opt_code) {
- case DNS_OPT_T_ECS: {
- struct dns_opt_ecs ecs;
- ret = _dns_decode_opt_ecs(context, &ecs, opt_len);
- if (ret != 0) {
- tlog(TLOG_ERROR, "decode ecs failed.");
- return -1;
- }
- ret = dns_add_OPT_ECS(packet, &ecs);
- if (ret != 0) {
- tlog(TLOG_ERROR, "add ecs failed.");
- return -1;
- }
- } break;
- case DNS_OPT_T_COOKIE: {
- struct dns_opt_cookie cookie;
- ret = _dns_decode_opt_cookie(context, &cookie, opt_len);
- if (ret != 0) {
- tlog(TLOG_ERROR, "decode cookie failed.");
- return -1;
- }
- } break;
- case DNS_OPT_T_TCP_KEEPALIVE: {
- unsigned short timeout = 0;
- ret = _dns_decode_opt_tcp_keepalive(context, &timeout, opt_len);
- if (ret != 0) {
- tlog(TLOG_ERROR, "decode tcp keepalive failed.");
- return -1;
- }
- ret = dns_add_OPT_TCP_KEEPALIVE(packet, timeout);
- if (ret != 0) {
- tlog(TLOG_ERROR, "add tcp keepalive failed.");
- return -1;
- }
- } break;
- case DNS_OPT_T_PADDING:
- context->ptr += opt_len;
- break;
- default:
- context->ptr += opt_len;
- tlog(TLOG_DEBUG, "DNS opt type = %d not supported", opt_code);
- break;
- }
- }
- return 0;
- }
- static int _dns_encode_HTTPS(struct dns_context *context, struct dns_rrs *rrs)
- {
- int ret = 0;
- int qtype = 0;
- int qclass = 0;
- char domain[DNS_MAX_CNAME_LEN];
- char target[DNS_MAX_CNAME_LEN] = {0};
- unsigned char *rr_len_ptr = NULL;
- unsigned char *start = NULL;
- unsigned char *rr_start = NULL;
- int ttl = 0;
- int priority = 0;
- struct dns_https_param *param = NULL;
- ret =
- dns_get_HTTPS_svcparm_start(rrs, ¶m, domain, DNS_MAX_CNAME_LEN, &ttl, &priority, target, DNS_MAX_CNAME_LEN);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "get https param failed.");
- return 0;
- }
- qtype = DNS_T_HTTPS;
- qclass = DNS_C_IN;
- ret = _dns_encode_rr_head(context, domain, qtype, qclass, ttl, 0, &rr_len_ptr);
- if (ret < 0) {
- return -1;
- }
- rr_start = context->ptr;
- if (_dns_left_len(context) < 2) {
- tlog(TLOG_ERROR, "left len is invalid.");
- return -1;
- }
- _dns_write_short(&context->ptr, priority);
- ret = _dns_encode_domain(context, target);
- if (ret < 0) {
- return -1;
- }
- start = context->ptr;
- for (; param != NULL; param = dns_get_HTTPS_svcparm_next(rrs, param)) {
- if (context->ptr - start > rrs->len || _dns_left_len(context) <= 0) {
- return -1;
- }
- if (param->len + 4 > _dns_left_len(context)) {
- return -1;
- }
- _dns_write_short(&context->ptr, param->key);
- _dns_write_short(&context->ptr, param->len);
- switch (param->key) {
- case DNS_HTTPS_T_MANDATORY:
- case DNS_HTTPS_T_NO_DEFAULT_ALPN:
- case DNS_HTTPS_T_ALPN:
- case DNS_HTTPS_T_PORT:
- case DNS_HTTPS_T_IPV4HINT:
- case DNS_HTTPS_T_ECH:
- case DNS_HTTPS_T_IPV6HINT: {
- memcpy(context->ptr, param->value, param->len);
- context->ptr += param->len;
- } break;
- default:
- /* skip unknown key */
- context->ptr -= 4;
- break;
- }
- }
- if (_dns_left_len(context) < 2) {
- return -1;
- }
- _dns_write_short(&rr_len_ptr, context->ptr - rr_start);
- return 0;
- }
- static int _dns_decode_HTTPS(struct dns_context *context, const char *domain, dns_rr_type type, unsigned int ttl,
- int rr_len)
- {
- unsigned char *start = context->ptr;
- struct dns_packet *packet = context->packet;
- int ret = 0;
- unsigned short priority;
- unsigned short key;
- unsigned short value_len;
- unsigned char *value = NULL;
- char target[DNS_MAX_CNAME_LEN] = {0};
- struct dns_rr_nested param;
- if (rr_len < 2) {
- tlog(TLOG_DEBUG, "https len is invalid.");
- return -1;
- }
- priority = _dns_read_short(&context->ptr);
- ret = _dns_decode_domain(context, target, sizeof(target));
- if (ret < 0) {
- return -1;
- }
- dns_add_HTTPS_start(¶m, packet, DNS_RRS_AN, domain, ttl, priority, target);
- while (context->ptr - start < rr_len) {
- if (_dns_left_len(context) < 4) {
- tlog(TLOG_WARN, "data length is invalid, %d:%d", _dns_left_len(context),
- (int)(context->ptr - context->data));
- return -1;
- }
- key = _dns_read_short(&context->ptr);
- value_len = _dns_read_short(&context->ptr);
- value = context->ptr;
- if (_dns_left_len(context) < value_len) {
- tlog(TLOG_ERROR, "read https data failed, svcParam key = %d, https_len = %d", key, value_len);
- return -1;
- }
- switch (key) {
- case DNS_HTTPS_T_MANDATORY:
- case DNS_HTTPS_T_ALPN:
- case DNS_HTTPS_T_NO_DEFAULT_ALPN:
- case DNS_HTTPS_T_PORT:
- case DNS_HTTPS_T_IPV4HINT:
- case DNS_HTTPS_T_ECH:
- case DNS_HTTPS_T_IPV6HINT: {
- dns_HTTPS_add_raw(¶m, key, value, value_len);
- } break;
- default:
- tlog(TLOG_DEBUG, "DNS HTTPS key = %d not supported", key);
- break;
- }
- context->ptr += value_len;
- }
- dns_add_HTTPS_end(¶m);
- return 0;
- }
- static int _dns_decode_qd(struct dns_context *context)
- {
- struct dns_packet *packet = context->packet;
- int len = 0;
- int qtype = 0;
- int qclass = 0;
- char domain[DNS_MAX_CNAME_LEN];
- len = _dns_decode_qr_head(context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass);
- if (len < 0) {
- return -1;
- }
- len = dns_add_domain(packet, domain, qtype, qclass);
- if (len < 0) {
- return -1;
- }
- return 0;
- }
- static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
- {
- int ret = 0;
- int qtype = 0;
- int qclass = 0;
- int ttl = 0;
- int rr_len = 0;
- char domain[DNS_MAX_CNAME_LEN];
- struct dns_packet *packet = context->packet;
- unsigned char *start = NULL;
- /* decode rr head */
- ret = _dns_decode_rr_head(context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len);
- if (ret < 0 || qclass < 0) {
- tlog(TLOG_DEBUG, "decode head failed.");
- return -1;
- }
- start = context->ptr;
- /* decode answer */
- switch (qtype) {
- case DNS_T_A: {
- unsigned char addr[DNS_RR_A_LEN];
- ret = _dns_decode_raw(context, addr, sizeof(addr));
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode A failed, %s, len: %d:%d", domain, (int)(context->ptr - context->data),
- _dns_left_len(context));
- return -1;
- }
- ret = dns_add_A(packet, type, domain, ttl, addr);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "add A failed, %s", domain);
- return -1;
- }
- } break;
- case DNS_T_CNAME: {
- char cname[DNS_MAX_CNAME_LEN];
- ret = _dns_decode_CNAME(context, cname, DNS_MAX_CNAME_LEN);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode CNAME failed, %s, len: %d:%d", domain, (int)(context->ptr - context->data),
- _dns_left_len(context));
- return -1;
- }
- ret = dns_add_CNAME(packet, type, domain, ttl, cname);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "add CNAME failed, %s", domain);
- return -1;
- }
- } break;
- case DNS_T_SOA: {
- struct dns_soa soa;
- ret = _dns_decode_SOA(context, &soa);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode SOA failed, %s", domain);
- return -1;
- }
- ret = dns_add_SOA(packet, type, domain, ttl, &soa);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "add SOA failed, %s", domain);
- return -1;
- }
- } break;
- case DNS_T_NS: {
- char ns[DNS_MAX_CNAME_LEN];
- ret = _dns_decode_CNAME(context, ns, DNS_MAX_CNAME_LEN);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode NS failed, %s", domain);
- return -1;
- }
- ret = dns_add_NS(packet, type, domain, ttl, ns);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "add NS failed, %s", domain);
- return -1;
- }
- } break;
- case DNS_T_PTR: {
- char name[DNS_MAX_CNAME_LEN];
- ret = _dns_decode_CNAME(context, name, DNS_MAX_CNAME_LEN);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode PTR failed, %s", domain);
- return -1;
- }
- ret = dns_add_PTR(packet, type, domain, ttl, name);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "add PTR failed, %s", domain);
- return -1;
- }
- } break;
- case DNS_T_AAAA: {
- unsigned char addr[DNS_RR_AAAA_LEN];
- ret = _dns_decode_raw(context, addr, sizeof(addr));
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode AAAA failed, %s", domain);
- return -1;
- }
- ret = dns_add_AAAA(packet, type, domain, ttl, addr);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "add AAAA failed, %s", domain);
- return -1;
- }
- } break;
- case DNS_T_SRV: {
- unsigned short priority = 0;
- unsigned short weight = 0;
- unsigned short port = 0;
- char target[DNS_MAX_CNAME_LEN];
- ret = _dns_decode_SRV(context, &priority, &weight, &port, target, DNS_MAX_CNAME_LEN);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode SRV failed, %s", domain);
- return -1;
- }
- ret = dns_add_SRV(packet, type, domain, ttl, priority, weight, port, target);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "add SRV failed, %s", domain);
- return -1;
- }
- } break;
- case DNS_T_OPT: {
- unsigned char *opt_start = context->ptr;
- ret = _dns_decode_opt(context, type, ttl, rr_len);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode opt failed, %s", domain);
- return -1;
- }
- if (context->ptr - opt_start != rr_len) {
- tlog(TLOG_DEBUG, "opt length mismatch, %s\n", domain);
- return -1;
- }
- dns_set_OPT_option(packet, ttl);
- dns_set_OPT_payload_size(packet, qclass);
- } break;
- case DNS_T_HTTPS: {
- unsigned char *https_start = context->ptr;
- ret = _dns_decode_HTTPS(context, domain, type, ttl, rr_len);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode HTTPS failed, %s", domain);
- return -1;
- }
- if (context->ptr - https_start != rr_len) {
- tlog(TLOG_DEBUG, "opt length mismatch, %s\n", domain);
- return -1;
- }
- } break;
- default: {
- unsigned char raw_data[1024];
- if (_dns_left_len(context) < rr_len || rr_len >= (int)sizeof(raw_data)) {
- tlog(TLOG_DEBUG, "length mismatch\n");
- return -1;
- }
- ret = _dns_decode_raw(context, raw_data, rr_len);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode A failed, %s", domain);
- return -1;
- }
- ret = _dns_add_RAW(packet, type, qtype, domain, ttl, raw_data, rr_len);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "add raw failed, %s", domain);
- return -1;
- }
- tlog(TLOG_DEBUG, "DNS type = %d not supported", qtype);
- break;
- }
- }
- if (context->ptr - start != rr_len) {
- tlog(TLOG_DEBUG, "length mismatch, %s, %ld:%d", domain, (long)(context->ptr - start), rr_len);
- return -1;
- }
- return 0;
- }
- static int _dns_encode_qd(struct dns_context *context, struct dns_rrs *rrs)
- {
- int ret = 0;
- int qtype = 0;
- int qclass = 0;
- char domain[DNS_MAX_CNAME_LEN];
- struct dns_context data_context;
- _dns_init_context_by_rrs(rrs, &data_context);
- ret = _dns_get_qr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass);
- if (ret < 0) {
- return -1;
- }
- ret = _dns_encode_qr_head(context, domain, qtype, qclass);
- if (ret < 0) {
- return -1;
- }
- if (domain[0] == '-') {
- /* for google and cloudflare */
- unsigned char *ptr = context->ptr - 7;
- memcpy(ptr, "\xC0\x12", 2);
- ptr += 2;
- _dns_write_short(&ptr, qtype);
- _dns_write_short(&ptr, qclass);
- context->ptr = ptr;
- }
- return 0;
- }
- static int _dns_encode_an(struct dns_context *context, struct dns_rrs *rrs)
- {
- int ret = 0;
- switch (rrs->type) {
- case DNS_T_A:
- case DNS_T_AAAA: {
- ret = _dns_encode_raw(context, rrs);
- if (ret < 0) {
- return -1;
- }
- } break;
- case DNS_T_CNAME:
- case DNS_T_PTR:
- ret = _dns_encode_CNAME(context, rrs);
- if (ret < 0) {
- return -1;
- }
- break;
- case DNS_T_SOA:
- ret = _dns_encode_SOA(context, rrs);
- if (ret < 0) {
- return -1;
- }
- break;
- case DNS_T_SRV:
- ret = _dns_encode_SRV(context, rrs);
- if (ret < 0) {
- return -1;
- }
- break;
- case DNS_T_HTTPS:
- ret = _dns_encode_HTTPS(context, rrs);
- if (ret < 0) {
- return -1;
- }
- break;
- default:
- ret = _dns_encode_raw(context, rrs);
- if (ret < 0) {
- return -1;
- }
- break;
- }
- return 0;
- }
- static int _dns_decode_body(struct dns_context *context)
- {
- struct dns_packet *packet = context->packet;
- struct dns_head *head = &packet->head;
- int i = 0;
- int ret = 0;
- int count = 0;
- count = head->qdcount;
- head->qdcount = 0;
- for (i = 0; i < count; i++) {
- ret = _dns_decode_qd(context);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode qd failed.");
- return -1;
- }
- }
- count = head->ancount;
- head->ancount = 0;
- for (i = 0; i < count; i++) {
- ret = _dns_decode_an(context, DNS_RRS_AN);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode an failed.");
- return -1;
- }
- }
- count = head->nscount;
- head->nscount = 0;
- for (i = 0; i < count; i++) {
- ret = _dns_decode_an(context, DNS_RRS_NS);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode ns failed.");
- return -1;
- }
- }
- count = head->nrcount;
- head->nrcount = 0;
- for (i = 0; i < count; i++) {
- ret = _dns_decode_an(context, DNS_RRS_NR);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode nr failed.");
- return -1;
- }
- }
- return 0;
- }
- static int _dns_encode_body(struct dns_context *context)
- {
- struct dns_packet *packet = context->packet;
- struct dns_head *head = &packet->head;
- int i = 0;
- int len = 0;
- struct dns_rrs *rrs = NULL;
- int count = 0;
- rrs = dns_get_rrs_start(packet, DNS_RRS_QD, &count);
- head->qdcount = count;
- for (i = 0; i < count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
- len = _dns_encode_qd(context, rrs);
- if (len < 0) {
- return -1;
- }
- }
- rrs = dns_get_rrs_start(packet, DNS_RRS_AN, &count);
- head->ancount = count;
- for (i = 0; i < count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
- len = _dns_encode_an(context, rrs);
- if (len < 0) {
- return -1;
- }
- }
- rrs = dns_get_rrs_start(packet, DNS_RRS_NS, &count);
- head->nscount = count;
- for (i = 0; i < count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
- len = _dns_encode_an(context, rrs);
- if (len < 0) {
- return -1;
- }
- }
- rrs = dns_get_rrs_start(packet, DNS_RRS_NR, &count);
- head->nrcount = count;
- for (i = 0; i < count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
- len = _dns_encode_an(context, rrs);
- if (len < 0) {
- return -1;
- }
- }
- rrs = dns_get_rrs_start(packet, DNS_RRS_OPT, &count);
- if (count > 0 || packet->payloadsize > 0) {
- len = _dns_encode_opts(packet, context, rrs, count);
- if (len < 0) {
- return -1;
- }
- head->nrcount++;
- }
- return 0;
- }
- int dns_packet_init(struct dns_packet *packet, int size, struct dns_head *head)
- {
- struct dns_head *init_head = &packet->head;
- if (size < (int)sizeof(*packet)) {
- return -1;
- }
- memset(packet, 0, size);
- packet->size = size;
- init_head->id = head->id;
- init_head->qr = head->qr;
- init_head->opcode = head->opcode;
- init_head->aa = head->aa;
- init_head->tc = head->tc;
- init_head->rd = head->rd;
- init_head->ra = head->ra;
- init_head->z = head->z;
- init_head->ad = head->ad;
- init_head->cd = head->cd;
- init_head->rcode = head->rcode;
- packet->questions = DNS_RR_END;
- packet->answers = DNS_RR_END;
- packet->nameservers = DNS_RR_END;
- packet->additional = DNS_RR_END;
- packet->optional = DNS_RR_END;
- packet->optcount = 0;
- packet->payloadsize = 0;
- return 0;
- }
- int dns_decode_head_only(struct dns_packet *packet, int maxsize, unsigned char *data, int size)
- {
- struct dns_head *head = &packet->head;
- struct dns_context context;
- int ret = 0;
- memset(&context, 0, sizeof(context));
- memset(packet, 0, sizeof(*packet));
- context.data = data;
- context.packet = packet;
- context.ptr = data;
- context.maxsize = size;
- context.namedict = &packet->namedict;
- ret = dns_packet_init(packet, maxsize, head);
- if (ret != 0) {
- return -1;
- }
- ret = _dns_decode_head(&context);
- if (ret < 0) {
- return -1;
- }
- packet->size = context.ptr - context.data + sizeof(*packet);
- return 0;
- }
- int dns_decode(struct dns_packet *packet, int maxsize, unsigned char *data, int size)
- {
- struct dns_head *head = &packet->head;
- struct dns_context context;
- int ret = 0;
- memset(&context, 0, sizeof(context));
- memset(packet, 0, sizeof(*packet));
- context.data = data;
- context.packet = packet;
- context.ptr = data;
- context.maxsize = size;
- context.namedict = &packet->namedict;
- ret = dns_packet_init(packet, maxsize, head);
- if (ret != 0) {
- return -1;
- }
- ret = _dns_decode_head(&context);
- if (ret < 0) {
- return -1;
- }
- ret = _dns_decode_body(&context);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode body failed.\n");
- return -1;
- }
- packet->size = context.ptr - context.data + sizeof(*packet);
- return 0;
- }
- int dns_encode(unsigned char *data, int size, struct dns_packet *packet)
- {
- int ret = 0;
- struct dns_context context;
- struct dns_packet_dict namedict;
- memset(&context, 0, sizeof(context));
- memset(&namedict, 0, sizeof(namedict));
- context.data = data;
- context.packet = packet;
- context.ptr = data;
- context.maxsize = size;
- context.namedict = &namedict;
- ret = _dns_encode_head(&context);
- if (ret < 0) {
- return -1;
- }
- ret = _dns_encode_body(&context);
- if (ret < 0) {
- return -1;
- }
- ret = _dns_encode_head_count(&context);
- if (ret < 0) {
- return -1;
- }
- return context.ptr - context.data;
- }
- static int _dns_update_an(struct dns_context *context, dns_rr_type type, struct dns_update_param *param)
- {
- int ret = 0;
- int qtype = 0;
- int qclass = 0;
- int ttl = 0;
- int rr_len = 0;
- char domain[DNS_MAX_CNAME_LEN];
- unsigned char *start = NULL;
- /* decode rr head */
- ret = _dns_decode_rr_head(context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode head failed.");
- return -1;
- }
- start = context->ptr;
- switch (qtype) {
- case DNS_T_OPT:
- break;
- default: {
- unsigned char *ttl_ptr = start - sizeof(int) - sizeof(short);
- if (param->ip_ttl < 0) {
- break;
- }
- _dns_write_int(&ttl_ptr, param->ip_ttl);
- } break;
- }
- context->ptr += rr_len;
- if (context->ptr - start != rr_len) {
- tlog(TLOG_ERROR, "length mismatch , %s, %ld:%d", domain, (long)(context->ptr - start), rr_len);
- return -1;
- }
- return 0;
- }
- static int _dns_update_body(struct dns_context *context, struct dns_update_param *param)
- {
- struct dns_packet *packet = context->packet;
- struct dns_head *head = &packet->head;
- int i = 0;
- int ret = 0;
- int count = 0;
- count = head->qdcount;
- head->qdcount = 0;
- for (i = 0; i < count; i++) {
- char domain[DNS_MAX_CNAME_LEN];
- int qtype = 0;
- int qclass = 0;
- int len = 0;
- len = _dns_decode_qr_head(context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass);
- if (len < 0) {
- tlog(TLOG_DEBUG, "update qd failed.");
- return -1;
- }
- }
- count = head->ancount;
- head->ancount = 0;
- for (i = 0; i < count; i++) {
- ret = _dns_update_an(context, DNS_RRS_AN, param);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "update an failed.");
- return -1;
- }
- }
- count = head->nscount;
- head->nscount = 0;
- for (i = 0; i < count; i++) {
- ret = _dns_update_an(context, DNS_RRS_NS, param);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "update ns failed.");
- return -1;
- }
- }
- count = head->nrcount;
- head->nrcount = 0;
- for (i = 0; i < count; i++) {
- ret = _dns_update_an(context, DNS_RRS_NR, param);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "update nr failed.");
- return -1;
- }
- }
- return 0;
- }
- static int _dns_update_id(unsigned char *data, int size, struct dns_update_param *param)
- {
- unsigned char *ptr = data;
- _dns_write_short(&ptr, param->id);
- return 0;
- }
- int dns_packet_update(unsigned char *data, int size, struct dns_update_param *param)
- {
- struct dns_packet packet;
- int maxsize = sizeof(packet);
- struct dns_head *head = &packet.head;
- struct dns_context context;
- int ret = 0;
- memset(&context, 0, sizeof(context));
- memset(&packet, 0, sizeof(packet));
- context.data = data;
- context.packet = &packet;
- context.ptr = data;
- context.maxsize = size;
- ret = dns_packet_init(&packet, maxsize, head);
- if (ret != 0) {
- return -1;
- }
- ret = _dns_decode_head(&context);
- if (ret < 0) {
- return -1;
- }
- ret = _dns_update_id(data, size, param);
- if (ret < 0) {
- return -1;
- }
- ret = _dns_update_body(&context, param);
- if (ret < 0) {
- tlog(TLOG_DEBUG, "decode body failed.\n");
- return -1;
- }
- return 0;
- }
|