From: Jelte Jansen Date: Wed, 25 Jan 2006 15:30:50 +0000 (+0000) Subject: added miniminimininameserver X-Git-Tag: release-1.1.0~379 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f8d38f61ef164f31d31aed86e79509d5d3f718c7;p=thirdparty%2Fldns.git added miniminimininameserver only udp, just answers with any match from the zonefile no error checking will probably not work on systems other than this linux box but it's a start :) --- diff --git a/examples/Makefile.in b/examples/Makefile.in index f59006e5..5dd5efdd 100644 --- a/examples/Makefile.in +++ b/examples/Makefile.in @@ -37,7 +37,8 @@ SOURCES = ldns-read-zone.c \ ldns-threshold-update.c \ ldns-zsplit.c \ ldns-zcat.c \ - ldns-dpa.c + ldns-dpa.c \ + ldnsd.c PROGRAMS=$(SOURCES:.c=) @@ -85,6 +86,9 @@ ldns-zsplit: ldns-zsplit.o ldns-zcat: ldns-zcat.o $(LINK) -o $@ $+ +ldnsd: ldnsd.o + $(LINK) -o $@ $+ + ldns-threshold-update: ldns-threshold-update.o $(LINK) -o $@ $+ diff --git a/examples/ldnsd.c b/examples/ldnsd.c new file mode 100644 index 00000000..83af8fe3 --- /dev/null +++ b/examples/ldnsd.c @@ -0,0 +1,224 @@ +/* + * ldnsd. Light-weight DNS daemon + * + * Tiny dns server to show how a real one could be built. + * + * (c) NLnet Labs, 2005 + * See the file LICENSE for the license + */ + +#include "config.h" +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#define INBUF_SIZE 4096 + +void usage(FILE *output) +{ + fprintf(output, "Usage: ldnsd \n"); + fprintf(output, "Listens on the specified port and answers queries for the given zone\n"); + fprintf(output, "This is NOT a full-fledged authoritative nameserver!\n"); +} + +static int udp_bind(int sock, int port, const char *my_address) +{ + struct sockaddr_in addr; + + addr.sin_family = AF_INET; + addr.sin_port = htons((uint16_t)port); + addr.sin_addr.s_addr = INADDR_ANY; +// if (join_mcast(sock, &addr) == -1) { return -1; } +/* + if (join_group(sock, inet_addr(my_address), INADDR_ANY)) { + perror("setsockopt"); + } else { + fprintf(stderr, "Ok.\n"); + } +*/ + return bind(sock, (struct sockaddr *)&addr, (socklen_t) sizeof(addr)); +} + +/* this will probably be moved to a better place in the library itself */ +ldns_rr_list * +get_rrset(const ldns_zone *zone, const ldns_rdf *owner_name, const ldns_rr_type qtype, const ldns_rr_class qclass) +{ + uint16_t i; + ldns_rr_list *rrlist = ldns_rr_list_new(); + ldns_rr *cur_rr; + if (!zone || !owner_name) { + fprintf(stderr, "Warning: get_rrset called with NULL zone or owner name\n"); + return rrlist; + } + + for (i = 0; i < ldns_zone_rr_count(zone); i++) { + cur_rr = ldns_rr_list_rr(ldns_zone_rrs(zone), i); + if (ldns_dname_compare(ldns_rr_owner(cur_rr), owner_name) == 0 && + ldns_rr_get_class(cur_rr) == qclass && + ldns_rr_get_type(cur_rr) == qtype + ) { + ldns_rr_list_push_rr(rrlist, ldns_rr_clone(cur_rr)); + } + } + + printf("Found rrset of %u rrs\n", (unsigned int) ldns_rr_list_rr_count(rrlist)); + + return rrlist; +} + +int +main(int argc, char **argv) +{ + /* arguments */ + int port; + const char *zone_name; + const char *zone_file; + + /* network */ + int sock; + size_t nb; + struct sockaddr addr_me; + struct sockaddr addr_him; + socklen_t hislen; + const char *my_address; + uint8_t inbuf[INBUF_SIZE]; + uint8_t *outbuf; + + /* dns */ + ldns_status status; + ldns_pkt *query_pkt; + ldns_pkt *answer_pkt; + size_t answer_size; + ldns_rr *query_rr; + ldns_rr_list *answer_qr; + ldns_rr_list *answer_an; + ldns_rr_list *answer_ns; + ldns_rr_list *answer_ad; + + /* zone */ + ldns_zone *zone; + int line_nr; + FILE *zone_fp; + + /* use this to listen on specified interfaces later? */ + my_address = NULL; + + if (argc < 4) { + usage(stdout); + exit(EXIT_FAILURE); + } else { + port = atoi(argv[1]); + if (port < 1) { + usage(stdout); + } + zone_name = argv[2]; + zone_file = argv[3]; + } + + printf("Reading zone file %s\n", zone_file); + zone_fp = fopen(zone_file, "r"); + if (!zone_fp) { + fprintf(stderr, "Unable to open %s: %s\n", zone_file, strerror(errno)); + exit(EXIT_FAILURE); + } + + line_nr = 0; + zone = ldns_zone_new_frm_fp_l(zone_fp, NULL, 0, LDNS_RR_CLASS_IN, &line_nr); + + if (!zone) { + printf("Zone reader failed, aborting\n"); + exit(EXIT_FAILURE); + } else { + printf("Read %u resource records in zone file\n", (unsigned int) ldns_zone_rr_count(zone)); + } + + fclose(zone_fp); + + + printf("Listening on port %d\n", port); + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + fprintf(stderr, "%s: socket(): %s\n", argv[0], strerror(errno)); + exit(1); + } + + memset(&addr_me, 0, sizeof(addr_me)); + + /* bind: try all ports in that range */ + if (udp_bind(sock, port, my_address)) { + fprintf(stderr, "%s: cannot bind(): %s\n", argv[0], strerror(errno)); + } + + /* Done. Now receive */ + while (1) { + nb = (size_t) recvfrom(sock, inbuf, INBUF_SIZE, 0, &addr_him, &hislen); + if (nb < 1) { + fprintf(stderr, "%s: recvfrom(): %s\n", + argv[0], strerror(errno)); + exit(1); + } + + /* + show(inbuf, nb, nn, hp, sp, ip, bp); + */ + + printf("Got query of %u bytes\n", (unsigned int) nb); + status = ldns_wire2pkt(&query_pkt, inbuf, nb); + if (status != LDNS_STATUS_OK) { + printf("Got bad packet: %s\n", ldns_get_errorstr_by_id(status)); + } else { + ldns_pkt_print(stdout, query_pkt); + } + + query_rr = ldns_rr_list_rr(ldns_pkt_question(query_pkt), 0); + printf("QUERY RR: \n"); + ldns_rr_print(stdout, query_rr); + + answer_qr = ldns_rr_list_new(); + ldns_rr_list_push_rr(answer_qr, ldns_rr_clone(query_rr)); + + answer_an = get_rrset(zone, ldns_rr_owner(query_rr), ldns_rr_get_type(query_rr), ldns_rr_get_class(query_rr)); + answer_pkt = ldns_pkt_new(); + + answer_ns = ldns_rr_list_new(); + + answer_ad = ldns_rr_list_new(); + + ldns_pkt_set_qr(answer_pkt, 1); + ldns_pkt_set_aa(answer_pkt, 1); + ldns_pkt_set_id(answer_pkt, ldns_pkt_id(query_pkt)); + + /* aren't there push_rr(section) functions? */ + /* and why isn't the count automatically updated? */ + ldns_pkt_set_question(answer_pkt, answer_qr); + ldns_pkt_set_qdcount(answer_pkt, ldns_rr_list_rr_count(answer_qr)); + ldns_pkt_set_answer(answer_pkt, answer_an); + ldns_pkt_set_ancount(answer_pkt, ldns_rr_list_rr_count(answer_an)); + ldns_pkt_set_authority(answer_pkt, answer_ns); + ldns_pkt_set_nscount(answer_pkt, ldns_rr_list_rr_count(answer_ns)); + ldns_pkt_set_additional(answer_pkt, answer_ad); + ldns_pkt_set_arcount(answer_pkt, ldns_rr_list_rr_count(answer_ad)); + + status = ldns_pkt2wire(&outbuf, answer_pkt, &answer_size); + + printf("Answer packet size: %u bytes.\n", (unsigned int) answer_size); + if (status != LDNS_STATUS_OK) { + printf("Error creating answer: %s\n", ldns_get_errorstr_by_id(status)); + } else { + nb = (size_t) sendto(sock, outbuf, answer_size, 0, &addr_him, hislen); + } + + + + } + + return 0; +}