]> git.ipfire.org Git - thirdparty/ldns.git/commitdiff
Split up the tcp functionality in net.c
authorJelte Jansen <jeltejan@NLnetLabs.nl>
Wed, 23 Feb 2005 13:54:30 +0000 (13:54 +0000)
committerJelte Jansen <jeltejan@NLnetLabs.nl>
Wed, 23 Feb 2005 13:54:30 +0000 (13:54 +0000)
added run-test11, which is an example for an axfr transfer implementation
test with ./run-test11 jelte.nlnetlabs.nl 195.169.215.155

Makefile.in
ldns/net.h
net.c
run-test11.c [new file with mode: 0644]

index e85232b3d7f8cf888b9d94fe868030e461682867..796eccc34429053825a7dc77e1cc03dc2bfc5619 100644 (file)
@@ -43,7 +43,7 @@ LIBDNS_OBJECTS        =       $(LIBDNS_SOURCES:.c=.o)
 
 ALL_SOURCES    =       run-test0.c run-test1.c run-test2.c run-test3.c \
                        run-test4.c run-test5.c run-test6.c run-test7.c \
-                       run-test8.c run-test9.c \
+                       run-test8.c run-test9.c run-test10.c run-test11.c \
                        $(LIBDNS_SOURCES)
 
 TESTS          =       run-test0               \
@@ -56,7 +56,8 @@ TESTS         =       run-test0               \
                        run-test7               \
                        run-test8               \
                        run-test9               \
-                       run-test10              
+                       run-test10              \
+                       run-test11
 
 COMPILE                = $(CC) $(CPPFLAGS) $(CFLAGS)
 COMP_LIB       = $(LIBTOOL) $(CC) $(CPPFLAGS) $(CFLAGS)
@@ -105,6 +106,8 @@ run-test9:  run-test9.o $(LIBDNS_OBJECTS) $(LIBOBJS)
                $(LINK) ${LIBS} -o $@ $+
 run-test10:    run-test10.o $(LIBDNS_OBJECTS) $(LIBOBJS)
                $(LINK) ${LIBS} -o $@ $+
+run-test11:    run-test11.o $(LIBDNS_OBJECTS) $(LIBOBJS)
+               $(LINK) ${LIBS} -o $@ $+
 
 run-test-trace:        run-test-trace.o $(LIBDNS_OBJECTS) $(LIBOBJS)
                $(LINK) ${LIBS} -o $@ $+
@@ -159,8 +162,10 @@ test9: run-test9
        ./run-test9
 test10: run-test10
        ./run-test10
+test11: run-test11
+       ./run-test11
 
-test: test0 test1 test2 test3 test4 test5 test6 test7 test8 test9 test10
+test: test0 test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11
 
 ## No need for changes here
 
index d82253175dcae5c0d78f08fb204fbb8b20182d34..c0505b6ba987feaba062863540f678fa38f61e5f 100644 (file)
@@ -28,4 +28,8 @@ ldns_pkt * ldns_send_udp(ldns_buffer *, const struct sockaddr_storage *, socklen
 ldns_pkt * ldns_send_tcp(ldns_buffer *, const struct sockaddr_storage *, socklen_t);
 ldns_pkt * ldns_send(ldns_resolver *, ldns_pkt *);
 
+int ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen);
+ssize_t ldns_tcp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to, socklen_t tolen);
+ldns_pkt *ldns_tcp_read_packet(int sockfd);
+
 #endif  /* !_LDNS_NET_H */
diff --git a/net.c b/net.c
index 35387aaaf4f1459d33534df0521d45f8b1fed5e0..cae7dbb8178f01117f9074533bddb4ba9c890229 100644 (file)
--- a/net.c
+++ b/net.c
 #include "util.h"
 
 
-
-#if 0
-/* axfr is a hack - handle it different */
-ldns_pkt *
-ldns_sendbuf_axfr(ldns_buffer *buf, int *sockfd, struct sockaddr *dest)
-{
-       return NULL;
-}
-#endif 
-
 /**
  * Send to ptk to the nameserver at ipnumber. Return the data
  * as a ldns_pkt
@@ -203,25 +193,13 @@ ldns_send_udp(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t to
 }
 
 /**
- * Send a buffer to an ip using tcp and return the respons as a ldns_pkt
- * \param[in] qbin the ldns_buffer to be send
- * \param[in] to the ip addr to send to
- * \param[in] tolen length of the ip addr
- * \return a packet with the answer
+ * Create a tcp socket to the specified address
  */
-/* keep in mind that in DNS tcp messages the first 2 bytes signal the
- * amount data to expect
- */
-ldns_pkt *
-ldns_send_tcp(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen)
+int
+ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen)
 {
        int sockfd;
-       ssize_t bytes, total_bytes;
-       uint8_t *answer;
-       ldns_pkt *answer_pkt;
-       uint16_t answer_size;
-       uint8_t *sendbuf;
-
+       
         struct timeval timeout;
         
         timeout.tv_sec = LDNS_DEFAULT_TIMEOUT_SEC;
@@ -229,22 +207,32 @@ ldns_send_tcp(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t to
         
        if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
                perror("could not open socket");
-               return NULL;
+               return 0;
        }
 
         if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout,
                         (socklen_t) sizeof(timeout))) {
                 perror("setsockopt");
                 close(sockfd);
-                return NULL;
+                return 0;
         }
 
        if (connect(sockfd, (struct sockaddr*)to, tolen) == -1) {
                close(sockfd);
                perror("could not bind socket");
-               return NULL;
+               return 0;
        }
 
+       return sockfd;
+}
+
+
+ssize_t
+ldns_tcp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to, socklen_t tolen)
+{
+       uint8_t *sendbuf;
+       ssize_t bytes;
+
        /* add length of packet */
        sendbuf = XMALLOC(uint8_t, ldns_buffer_position(qbin) + 2);
        write_uint16(sendbuf, ldns_buffer_position(qbin));
@@ -258,68 +246,102 @@ ldns_send_tcp(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t to
        if (bytes == -1) {
                printf("error with sending\n");
                close(sockfd);
-               return NULL;
+               return 0;
        }
        if ((size_t) bytes != ldns_buffer_position(qbin)+2) {
                printf("amount of sent bytes mismatch\n");
                close(sockfd);
-               return NULL;
+               return 0;
        }
        
-       /* wait for an response*/
-       answer = XMALLOC(uint8_t, MAX_PACKETLEN);
-       if (!answer) {
-               printf("respons alloc error\n");
-               return NULL;
-       }
+       return bytes;
+}
 
-       /* first two bytes are the size of the wiredata,
-          we must be sure that we receive those */
-       total_bytes = 0;
-       while (total_bytes < 2) {
-               bytes = recv(sockfd, answer, MAX_PACKETLEN, 0);
+/**
+ * Creates a new ldns_pkt structure and reads the header data from the given
+ * socket
+ */
+ldns_pkt *
+ldns_tcp_read_packet(int sockfd)
+{
+       ldns_pkt *pkt;
+       uint8_t *wire;
+       uint16_t wire_size;
+       ssize_t bytes = 0;
+
+       wire = XMALLOC(uint8_t, 2);
+       while (bytes < 2) {
+               bytes = recv(sockfd, wire, 2, 0);
                if (bytes == -1) {
                        if (errno == EAGAIN) {
                                fprintf(stderr, "socket timeout\n");
                        }
                        perror("error receiving tcp packet");
-                       FREE(answer);
+                       FREE(pkt);
                        return NULL;
-               } else {
-                       total_bytes += bytes;
                }
        }
 
-       answer_size = read_uint16(answer);
+       wire_size = read_uint16(wire);
        
-       /* if we did not receive the whole packet in one tcp packet,
-          we must recv() on */
-       while (total_bytes < (ssize_t) (answer_size + 2)) {
-               bytes = recv(sockfd, answer + total_bytes, (size_t) (MAX_PACKETLEN - total_bytes), 0);
+       FREE(wire);
+       wire = XMALLOC(uint8_t, wire_size);
+       bytes = 0;
+
+       while (bytes < (ssize_t) wire_size) {
+               bytes += recv(sockfd, wire + bytes, (size_t) (wire_size - bytes), 0);
                if (bytes == -1) {
                        if (errno == EAGAIN) {
                                fprintf(stderr, "socket timeout\n");
                        }
                        perror("error receiving tcp packet");
-                       FREE(answer);
+                       FREE(wire);
                        return NULL;
-               } else {
-                       total_bytes += bytes;
                }
        }
 
-       close(sockfd);
-
-       /* resize accordingly */
-       XREALLOC(answer, uint8_t *, (size_t) total_bytes);
-
-        if (ldns_wire2pkt(&answer_pkt, answer+2, (size_t) answer_size) != 
+        if (ldns_wire2pkt(&pkt, wire, (size_t) wire_size) != 
                        LDNS_STATUS_OK) {
                printf("could not create packet\n");
+               FREE(wire);
                return NULL;
        } else {
-               ldns_pkt_set_size(answer_pkt, (size_t) bytes);
-               return answer_pkt;
+               ldns_pkt_set_size(pkt, (size_t) bytes);
+               FREE(wire);
+               return pkt;
        }
 }
 
+/**
+ * Send a buffer to an ip using tcp and return the respons as a ldns_pkt
+ * \param[in] qbin the ldns_buffer to be send
+ * \param[in] to the ip addr to send to
+ * \param[in] tolen length of the ip addr
+ * \return a packet with the answer
+ */
+/* keep in mind that in DNS tcp messages the first 2 bytes signal the
+ * amount data to expect
+ */
+ldns_pkt *
+ldns_send_tcp(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen)
+{
+       int sockfd;
+       ldns_pkt *answer;
+       
+       sockfd = ldns_tcp_connect(to, tolen);
+       
+       if (sockfd == 0) {
+               return NULL;
+       }
+       
+       if (ldns_tcp_send_query(qbin, sockfd, to, tolen) == 0) {
+               return NULL;
+       }
+       
+       answer = ldns_tcp_read_packet(sockfd);
+       
+       close(sockfd);
+       
+       return answer;
+}
+
diff --git a/run-test11.c b/run-test11.c
new file mode 100644 (file)
index 0000000..06bbbe8
--- /dev/null
@@ -0,0 +1,142 @@
+/**
+ * An example ldns program
+ *
+ * Setup a resolver
+ * Query a nameserver
+ * Print the result
+ */
+
+#include <config.h>
+#include <ldns/ldns.h>
+#include <ldns/dname.h>
+
+void
+print_usage(char *file)
+{
+       printf("AXFR example\n");
+       printf("Usage: %s <domain> <server ip>\n", file);
+       printf("ipv4 only atm\n");
+       exit(0);
+}
+
+int
+main(int argc, char **argv)
+{       
+        ldns_rdf *nameserver;
+
+        ldns_pkt *query;
+        ldns_buffer *query_wire;
+        
+        ldns_pkt *pkt;
+        int soa_count;
+        int connection;
+
+        struct sockaddr_storage *ns;
+        struct sockaddr_in *ns4;
+        struct sockaddr_in6 *ns6;
+        int ns_len = 0;
+
+        char *server_ip = NULL;
+        char *name = NULL;
+
+        ldns_rr_list *rr_list;
+        ldns_rr *cur_rr;
+        char *rr_str;
+        uint16_t i;
+        
+       /* Get the domain and the nameserver from the command line */
+        if (argc < 3) {
+               print_usage(argv[0]);
+       } else {
+               name = argv[1];
+               server_ip = argv[2];
+       }
+
+        nameserver  = ldns_rdf_new_frm_str(server_ip, LDNS_RDF_TYPE_A);
+       if (!nameserver) {
+               printf("Bad server ip\n");
+               return -1;
+       }
+
+        /* Create the query */
+       query = ldns_pkt_query_new_frm_str(name,
+                                          LDNS_RR_TYPE_AXFR,
+                                          LDNS_RR_CLASS_IN,
+                                          0);
+                                           
+       /* For AXFR, we have to make the connection ourselves */
+       ns = ldns_rdf2native_sockaddr_storage(nameserver);
+
+        ldns_rdf_free(nameserver);
+
+       /* Determine the address size.
+        * This is a nice one for a convenience funtion
+        */
+       switch(ns->ss_family) {
+               case AF_INET:
+                       ns4 = (struct sockaddr_in*) ns;
+                       ns4->sin_port = htons(53);
+                       ns_len = (socklen_t)sizeof(struct sockaddr_in);
+                       break;
+               case AF_INET6:
+                       ns6 = (struct sockaddr_in6*) ns;
+                       ns6->sin6_port = htons(53);
+                       ns_len = (socklen_t)sizeof(struct sockaddr_in6);
+                       break;
+                default:
+                       printf("unkown inet family\n");
+                       return -1;
+       }
+
+       connection = ldns_tcp_connect(ns, ns_len);
+       if (connection == 0) {
+               return -1;
+       }
+       
+       /* Convert the query to a buffer
+        * Is this necessary?
+        */
+       query_wire = ldns_buffer_new(MAX_PACKETLEN);
+       if (ldns_pkt2buffer_wire(query_wire, query) != LDNS_STATUS_OK) {
+               printf("Unable to create wire data for query\n");
+               return -1;
+       }
+       
+       /* Send the query */
+       ldns_tcp_send_query(query_wire, connection, ns, ns_len);
+       
+        ldns_pkt_free(query);
+        ldns_buffer_free(query_wire);
+
+       /* Print all the resource records we receive.
+        * The AXFR is done once the second SOA record is sent
+        */
+       soa_count = 0;
+       while (soa_count < 2) {
+               pkt = ldns_tcp_read_packet(connection);
+               
+               if (!pkt)  {
+                       printf("error reading packet\n");
+               } else {
+                       rr_list = ldns_pkt_answer(pkt);
+                       
+                       /* Counting the number of certain types of rrs might
+                        * be another good convenience function */
+                       for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
+                               cur_rr = ldns_rr_list_rr(rr_list, i);
+                               if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_SOA) {
+                                       soa_count++;
+                               }
+                               rr_str = ldns_rr2str(cur_rr);
+                               printf("%s\n", rr_str);
+                               FREE(rr_str);
+                       }
+                       ldns_pkt_free(pkt);
+               }
+       }
+
+       /* Don't forget to close the connection */
+       close(connection);
+
+        return 0;
+}