From 20207a9c182716443edd0fb38e25a360b0c04cbe Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Fri, 10 May 2013 15:40:25 -0400 Subject: [PATCH] Remove clutter --- experiments/EDLS.png | Bin 48154 -> 0 bytes experiments/edls.rkt | 242 --------- experiments/quadratic-choice-evt-fold.rkt | 25 - experiments/sfclient.rkt | 42 -- experiments/sfclient2.rkt | 14 - experiments/sfclient3.rkt | 24 - experiments/sfserver.rkt | 25 - experiments/sfserver2.rkt | 29 - prototype/dns.rkt | 619 ---------------------- prototype/mapping.rkt | 35 -- prototype/test-dns.rkt | 248 --------- prototype/test-mapping.rkt | 25 - simple-udp-service.rkt | 97 ---- simplified-driver.rkt | 156 ------ stress.rkt | 75 --- 15 files changed, 1656 deletions(-) delete mode 100644 experiments/EDLS.png delete mode 100644 experiments/edls.rkt delete mode 100644 experiments/quadratic-choice-evt-fold.rkt delete mode 100644 experiments/sfclient.rkt delete mode 100644 experiments/sfclient2.rkt delete mode 100644 experiments/sfclient3.rkt delete mode 100644 experiments/sfserver.rkt delete mode 100644 experiments/sfserver2.rkt delete mode 100644 prototype/dns.rkt delete mode 100644 prototype/mapping.rkt delete mode 100644 prototype/test-dns.rkt delete mode 100644 prototype/test-mapping.rkt delete mode 100644 simple-udp-service.rkt delete mode 100644 simplified-driver.rkt delete mode 100644 stress.rkt diff --git a/experiments/EDLS.png b/experiments/EDLS.png deleted file mode 100644 index e9601e2c336da4e013084d9a16143c5f40155635..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48154 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 value computation))) -;; program-meaning : (-> program (* (+ value error) resources) -;; expression-meaning : (-> expr env computation) -;; admin : (-> (* computation resources) (* (+ value error) resources)) -;; handler : (-> computation (-> value computation) computation) -;; -;; Handler is used to stitch stack frames together into a composed -;; continuation, something that we're doing here natively with -;; Racket's composable continuations. -;; -;; If we're going to make values self-representing, then we need to -;; ensure that all effects are disjoint from values. The way to do -;; that is to control the abort/prompt-tag protocol closely, so that -;; regular values returned are distinguished from actions thrown. That -;; way, no value is forbidden to the userland, including descriptions -;; of actions. - -;; Can we say that the *communications facility* in EDLS is -;; underpowered? It's point-to-point and relies on noninterference -;; between action-handling extensions. Since each extension is -;; logically managing its own resources, it feels like we have a kind -;; of network-layer here IF we enforce separation of the managed -;; resources so there are no cross-channels. -;; -;; The reason I'm interested in this approach is to get some kind of -;; objcap-oriented interface not only to the substrate but to the -;; extensions embedded in the substrate. Consider the DNS-server case, -;; where a socket needs to be opened and then straight-line -;; interactions with the socket take place. Now consider the DNS-proxy -;; case, where not only does a socket (or more than one!) need to be -;; created, but complex conversional contexts are built up as each -;; query arrives and is processed. As DJB observes, a single query can -;; in principle result in unbounded recursion as "glue" records are -;; looked up. It kind of makes sense to have each conversational -;; context as a separate entity, managing its own resources, embedded -;; in the substrate. - -(require racket/match) -(require racket/class) - -(define interactor<%> - (interface () - perform-action)) - -(define action-prompt (make-continuation-prompt-tag 'interactor-action)) - -(define (perform-action . action-pieces) - (call-with-composable-continuation - (lambda (k) - (abort-current-continuation action-prompt - (lambda () (values action-pieces k)))) - action-prompt)) - -(define (run/interactor boot interactor) - (call-with-continuation-barrier - (lambda () - (let loop ((next-step-thunk (lambda () (values (boot) #f))) - (interactor interactor)) - (define-values (computation-step-result computation-step-continuation) - (call-with-continuation-prompt next-step-thunk action-prompt)) - (cond - ((eq? computation-step-continuation #f) - ;; The computation is finished, and has yielded a result. - computation-step-result) - (else - ;; The computation is not finished, but is waiting for an - ;; action to complete. - (send interactor perform-action - computation-step-result - (lambda (action-result-value new-interactor) - (loop (lambda () (computation-step-continuation action-result-value)) - new-interactor)) - (lambda () - (error 'run/interactor "Action not interpretable by context: ~v" - computation-step-result))))))))) - -(define cells% - (class* object% (interactor<%>) - (init-field next-name) - (init-field mapping) - (super-new) - (define/public (perform-action action k-ok k-dnu) - (match action - (`(new ,initial-value) - (k-ok next-name (make-object cells% - (+ next-name 1) - (hash-set mapping next-name initial-value)))) - (`(get ,n) - (if (hash-has-key? mapping n) - (k-ok (hash-ref mapping n) this) - (error 'cells% "Cell name ~v not found (on get)" n))) - (`(set ,n ,new-value) - (if (hash-has-key? mapping n) - (k-ok new-value (make-object cells% - next-name - (hash-set mapping n new-value))) - (error 'cells% "Cell name ~v not found (on set)" n))) - (else - (k-dnu)))))) - -(define (new-cell [initial-value (void)]) - (perform-action 'new initial-value)) - -(define (get-cell c) - (perform-action 'get c)) - -(define (set-cell! c v) - (perform-action 'set c v)) - -(define (empty-cells) - (make-object cells% 0 (hash))) - -(define combine% - (class* object% (interactor<%>) - (init-field children) - (super-new) - (define/public (perform-action action k-ok k-dnu) - (let search ((remaining children) - (examined '())) - (cond - ((null? remaining) (k-dnu)) - (else - (define child (car remaining)) - (define rest (cdr remaining)) - (send child perform-action - action - (lambda (result new-child) - (k-ok result - (make-object combine% (append (reverse examined) (cons new-child rest))))) - (lambda () - (search rest (cons child examined)))))))))) - -(define (combine-interactors is) - (make-object combine% is)) - -(define udp% - (class* object% (interactor<%>) - (struct handle (socket)) ;; generative: new predicate etc. per udp% instance! - (super-new) - (define/public (perform-action action k-ok k-dnu) - (match action - (`(new) - (k-ok (handle (udp-open-socket #f #f)) this)) - (`(bind ,(handle s) ,port) - (k-ok (udp-bind! s #f port) this)) - (`(send ,(handle s) ,host ,port ,packet) - (k-ok (udp-send-to s host port packet) this)) - (`(recv ,(handle s) ,packet-size-limit) - (define buffer (make-bytes packet-size-limit)) - (define-values (packet-length source-hostname source-port) - (udp-receive! s buffer)) - (k-ok (list source-hostname source-port (subbytes buffer 0 packet-length)) this)) - (else (k-dnu)))))) - -(run/interactor (lambda () 1234) - (empty-cells)) - -(run/interactor (lambda () - (let ((x (new-cell))) - (set-cell! x 1) - (set-cell! x (+ 1 (get-cell x))) - (+ 1000 (get-cell x)))) - (empty-cells)) - -(run/interactor (lambda () - (let ((x (new-cell 'initial-x-value)) - (y (new-cell 'initial-y-value))) - (set-cell! x 1) - (set-cell! y 1000) - (set-cell! x (+ 1 (get-cell x))) - (+ (get-cell x) - (get-cell y)))) - (combine-interactors (list (empty-cells)))) diff --git a/experiments/quadratic-choice-evt-fold.rkt b/experiments/quadratic-choice-evt-fold.rkt deleted file mode 100644 index 2c8450c..0000000 --- a/experiments/quadratic-choice-evt-fold.rkt +++ /dev/null @@ -1,25 +0,0 @@ -(require srfi/1) - -(define (c v acc) acc) -(define (c v acc) (choice-evt never-evt acc)) -(define (c v acc) (choice-evt (handle-evt always-evt void) acc)) - -(define-values (c1 c2) (values values list)) -(define-values (c1 c2) (values (lambda (i) never-evt) choice-evt)) -(define-values (c1 c2) (values (lambda (i) (handle-evt always-evt void)) choice-evt)) - -(for-each (lambda (n) - (define limit (* 128 (expt 2 n))) - (write limit) - (newline) - (time (do ((i 0 (+ i 1)) - (e never-evt (c i e))) - ((= i limit) e)))) - (iota 16)) - -(for-each (lambda (n) - (define limit (* 128 (expt 2 n))) - (write limit) - (newline) - (time (apply c2 (map c1 (iota limit))))) - (iota 16)) \ No newline at end of file diff --git a/experiments/sfclient.rkt b/experiments/sfclient.rkt deleted file mode 100644 index ff19c63..0000000 --- a/experiments/sfclient.rkt +++ /dev/null @@ -1,42 +0,0 @@ -#lang racket/base - -(require "os-big-bang.rkt") -(require "os-udp.rkt") -(require "os-timer.rkt" racket/match) - -(define getter - (os-big-bang 'none - (send-message `(request create-echo-socket (udp new 0 65536))) - (subscribe/fresh sub - (message-handlers w - [`(reply create-echo-socket ,sname) - (transition w - (unsubscribe sub) - (send-message (udp-packet sname (udp-address "127.0.0.1" 5678) #"get")) - (send-message (set-timer 'timeout 500 #t)) - (subscribe 'reply-waiter - (message-handlers w - [(udp-packet source (== sname) reply-bytes) - (define counter (integer-bytes->integer reply-bytes #f)) - (write counter) - (newline) - (transition w - (send-message 'quit) - (unsubscribe 'reply-waiter))] - [(timer-expired 'timeout _) - (write 'timed-out) - (newline) - (transition w - (send-message 'quit) - (unsubscribe 'reply-waiter))])))])))) - -(ground-vm - (os-big-bang 'none - (spawn (os-big-bang 'none - (subscribe 'quit-waiter - (message-handlers w - ['quit - (exit)])))) - (spawn udp-driver) - (spawn (timer-driver)) - (spawn getter))) diff --git a/experiments/sfclient2.rkt b/experiments/sfclient2.rkt deleted file mode 100644 index c0bd55f..0000000 --- a/experiments/sfclient2.rkt +++ /dev/null @@ -1,14 +0,0 @@ -#lang racket/base - -(require racket/match) -(require racket/udp) - -(define s (udp-open-socket #f #f)) -(udp-send-to s "127.0.0.1" 5678 #"get") -(define buffer (make-bytes 8)) -(sync/timeout 0.5 - (wrap-evt (udp-receive!-evt s buffer) - (match-lambda - [(list 8 _ _) - (write (integer-bytes->integer buffer #f)) - (newline)]))) diff --git a/experiments/sfclient3.rkt b/experiments/sfclient3.rkt deleted file mode 100644 index f496a75..0000000 --- a/experiments/sfclient3.rkt +++ /dev/null @@ -1,24 +0,0 @@ -#lang racket/base - -(require racket/match) -(require racket/udp) - -(define s (udp-open-socket #f #f)) -(define buffer (make-bytes 8)) -(define nrepeats 3500) - -(for-each - (lambda (x) (write `(,x milliseconds in ,nrepeats repeats = - ,(exact->inexact (/ x nrepeats)))) (newline)) - (cdr - (call-with-values (lambda () - (time-apply - (lambda () - (for ([i (in-range nrepeats)]) - (udp-send-to s "127.0.0.1" 5678 #"get") - (sync/timeout 0.5 - (wrap-evt (udp-receive!-evt s buffer) - (match-lambda - [(list 8 _ _) 'ok]))))) - '())) - list))) diff --git a/experiments/sfserver.rkt b/experiments/sfserver.rkt deleted file mode 100644 index 0f028ea..0000000 --- a/experiments/sfserver.rkt +++ /dev/null @@ -1,25 +0,0 @@ -#lang racket - -(require "os-big-bang.rkt") -(require "os-udp.rkt") - -(define counter - (os-big-bang 0 - (send-message `(request create-echo-socket (udp new 5678 65536))) - (subscribe/fresh sub - (message-handlers current-counter - [`(reply create-echo-socket ,sname) - (transition current-counter - (unsubscribe sub) - (subscribe 'packet-handler - (message-handlers current-counter - [(udp-packet source (== sname) #"get") - (transition (+ current-counter 1) - (send-message - (udp-packet sname source - (integer->integer-bytes current-counter 8 #f))))])))])))) - -(ground-vm - (os-big-bang 'none - (spawn udp-driver) - (spawn counter))) diff --git a/experiments/sfserver2.rkt b/experiments/sfserver2.rkt deleted file mode 100644 index a3f93ec..0000000 --- a/experiments/sfserver2.rkt +++ /dev/null @@ -1,29 +0,0 @@ -#lang racket - -(require "os-big-bang.rkt") -(require "os-udp.rkt") - -(define (counter server-socket) - (os-big-bang 0 - (subscribe 'packet-handler - (message-handlers current-counter - [(udp-packet source (== server-socket) #"get") - (transition (+ current-counter 1) - (send-message - (udp-packet server-socket source - (integer->integer-bytes current-counter 8 #f))))])))) - -(define main - (os-big-bang 'no-state - (send-message `(request create-echo-socket (udp new 5678 65536))) - (subscribe/fresh sub - (message-handlers w - [`(reply create-echo-socket ,server-socket) - (transition w - (unsubscribe sub) - (spawn (counter server-socket)))])))) - -(ground-vm - (os-big-bang 'none - (spawn udp-driver) - (spawn main))) diff --git a/prototype/dns.rkt b/prototype/dns.rkt deleted file mode 100644 index 30d382b..0000000 --- a/prototype/dns.rkt +++ /dev/null @@ -1,619 +0,0 @@ -#lang racket/base - -(require (planet tonyg/bitsyntax)) -(require racket/udp) -(require racket/match) - -(require "mapping.rkt") - -;; Protocol data taken from RFC-1035. (See also RFC-1034.) -;; Blocks of text inside ... also from RFC-1035. -;; RFC-3596 specifies "DNS Extensions to Support IP Version 6". - -;; RFC-2782 specifies the DNS SRV record, though weirdly it omits a -;; wire-level definition of the format! Presumably people have just -;; copied what they see everyone else do here! - -(provide (struct-out dns-message) - (struct-out question) - (struct-out rr) - (struct-out hinfo) - (struct-out minfo) - (struct-out mx) - (struct-out soa) - (struct-out wks) - (struct-out srv) - - value->query-opcode query-opcode->value - value->query-response-code query-response-code->value - type->value value->type - qtype->value value->qtype - class->value value->class - qclass->value value->qclass - - packet->dns-message - dns-message->packet - - make-dns-query - make-dns-response - - raw-dns-query) - -;;--------------------------------------------------------------------------- -;; Data definitions - -;; A DomainName is a ListOf, representing a domain name. The -;; head of the list is the leftmost label; for example, www.google.com -;; is represented as '(#"www" #"google" #"com"). - -;; A ShortString is a String with length 255 or shorter. - -;; An IPv4 is a (vector Byte Byte Byte Byte), representing an IPv4 -;; address. For example, 127.0.0.1 is represented as (vector 127 0 0 -;; 1). - -;; An IPv6 is a Vector of length 16 containing Bytes, representing an -;; IPv6 address. For example, 2001:0db8:85a3:0000:0000:8a2e:0370:7334 -;; is represented as (vector #x20 #x01 #x0d #xb8 #x85 #xa3 #x00 #x00 -;; #x00 #x00 #x8a #x2e #x03 #x70 #x73 #x34). - -;; A DNSMessage is a -;; (dns-message Uint16 Direction Opcode Authoritativeness -;; Truncatedness RecursionDesired RecursionAvailable ResponseCode -;; ListOf ListOf ListOf ListOf). -;; -;; Interpreted as either a DNS request or reply, depending on the -;; Direction. -(struct dns-message (id - direction - opcode - authoritative - truncated - recursion-desired - recursion-available - response-code - questions - answers - authorities - additional) - #:transparent) - -;; A Question is a (question DomainName QueryType QueryClass), -;; representing a DNS question: "What are the RRs for the given name, -;; type and class?" -(struct question (name type class) #:transparent) - -;; An RR is a (rr DomainName RRType RRClass Uint32 RData), -;; representing a resource record. -(struct rr (name type class ttl rdata) #:transparent) - -;; An RData is one of -;; - an IPv4, an "A" record -;; - an IPv6, an "AAAA" record -;; - (hinfo ShortString ShortString), a host information record [O] -;; - (minfo DomainName DomainName), a mailbox information record [O] -;; - (mx Uint16 DomainName), a mail exchanger record -;; - (soa DomainName DomainName Uint32 Uint32 Uint32 Uint32 Uint32), a -;; start-of-authority record -;; - (wks IPv4 Byte Bytes), a Well-Known Service [O] -;; - (srv Uint16 Uint16 Uint16 DomainName), an "SRV" record -;; -;; In each case, the RData's variant MUST line up correctly with the -;; type field of any RR containing it. -;; -;; Many of these variants are obsolete in today's DNS database (marked -;; [O] above). -(struct hinfo (cpu os) #:transparent) -(struct minfo (rmailbx emailbx) #:transparent) -(struct mx (preference exchange) #:transparent) -(struct soa (mname rname serial refresh retry expire minimum) #:transparent) -(struct wks (address protocol bitmap) #:transparent) -(struct srv (priority weight port target) #:transparent) - -;; An Opcode is a Symbol or a Number, one of the possibilities given -;; in the following define-mapping. It represents a DNS message -;; operation; see the RFC for details. -(define-mapping value->query-opcode query-opcode->value - #:forward-default values - #:backward-default values - (0 query) - (1 iquery) - (2 status)) - -;; A ResponseCode is a Symbol or a Number, one of the possibilities -;; given in the following define-mapping. It represents the outcome of -;; a DNS query. -(define-mapping value->query-response-code query-response-code->value - (0 no-error) - (1 format-error) - (2 server-failure) - (3 name-error) - (4 not-implemented) - (5 refused)) - -;; An RRType is a Symbol or a Number, one of the possibilities given -;; in the following define-mapping. It represents the type of an -;; RR. When used in an RR with an RData, the RRType and the RData -;; variant must correspond. -(define-mapping type->value value->type - #:forward-default values - #:backward-default values - (a 1) - (ns 2) - (md 3) - (mf 4) - (cname 5) - (soa 6) - (mb 7) - (mg 8) - (mr 9) - (null 10) - (wks 11) - (ptr 12) - (hinfo 13) - (minfo 14) - (mx 15) - (txt 16) - (aaaa 28) - (srv 33)) - -;; A QueryType is a Symbol or Number (as given in the following -;; define-mapping) or an RRType. It specifies the kinds of records -;; being sought after in a DNS query. -(define-mapping qtype->value value->qtype - #:forward-default type->value - #:backward-default value->type - (axfr 252) - (mailb 253) - (maila 254) - (* 255)) - -;; An RRClass is a Symbol or a Number, one of the possibilities given -;; in the following define-mapping. It represents the "class" of DNS -;; records being discussed. All classes except 'in are obsolete in -;; today's DNS databases. -(define-mapping class->value value->class - #:forward-default values - #:backward-default values - (in 1) - (cs 2) - (ch 3) - (hs 4)) - -;; A QueryClass is a Symbol or Number (as given in the following -;; define-mapping) or an RRClass. It specifies the "class" of records -;; being sought after in a DNS query. -(define-mapping qclass->value value->qclass - #:forward-default class->value - #:backward-default value->class - (* 255)) - -;;--------------------------------------------------------------------------- -;; DNS message codec - -;; -;; All communications inside of the domain protocol are carried in a single -;; format called a message. The top level format of message is divided -;; into 5 sections (some of which are empty in certain cases) shown below: -;; -;; +---------------------+ -;; | Header | -;; +---------------------+ -;; | Question | the question for the name server -;; +---------------------+ -;; | Answer | RRs answering the question -;; +---------------------+ -;; | Authority | RRs pointing toward an authority -;; +---------------------+ -;; | Additional | RRs holding additional information -;; +---------------------+ -;; - -;; -;; The header contains the following fields: -;; -;; 1 1 1 1 1 1 -;; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | ID | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; |QR| Opcode |AA|TC|RD|RA| Z | RCODE | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | QDCOUNT | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | ANCOUNT | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | NSCOUNT | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | ARCOUNT | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; - -(define (bit->value n if0 if1) - (if (positive? n) if1 if0)) - -(define (value->bit b if0 if1) - (cond - ((eq? b if0) 0) - ((eq? b if1) 1) - (else (error 'value->bit "Value supplied is neither ~v nor ~v: ~v" if0 if1 b)))) - -(define (packet->dns-message packet) - (bit-string-case packet - ([ (id :: bits 16) - (qr :: bits 1) - (opcode :: bits 4) - (aa :: bits 1) - (tc :: bits 1) - (rd :: bits 1) - (ra :: bits 1) - (= 0 :: bits 3) - (rcode :: bits 4) - (qdcount :: bits 16) - (ancount :: bits 16) - (nscount :: bits 16) - (arcount :: bits 16) - (sections4 :: binary) ] - (let*-values (((q-section sections3) - (parse-section packet decode-question qdcount sections4)) - ((a-section sections2) - (parse-section packet decode-rr ancount sections3)) - ((auth-section sections1) - (parse-section packet decode-rr nscount sections2)) - ((additional-section sections0) - (parse-section packet decode-rr arcount sections1))) - (when (not (zero? (bit-string-length sections0))) - (error 'packet->dns-message "Packet too long")) - (dns-message id - (bit->value qr 'request 'response) - (value->query-opcode opcode) - (bit->value aa 'non-authoritative 'authoritative) - (bit->value tc 'not-truncated 'truncated) - (bit->value rd 'no-recursion-desired 'recursion-desired) - (bit->value ra 'no-recursion-available 'recursion-available) - (value->query-response-code rcode) - q-section - a-section - auth-section - additional-section))))) - -(define (dns-message->packet m) - (bit-string->bytes - (bit-string ((dns-message-id m) :: bits 16) - ((value->bit (dns-message-direction m) - 'request 'response) :: bits 1) - ((query-opcode->value (dns-message-opcode m)) :: bits 4) - ((value->bit (dns-message-authoritative m) - 'non-authoritative 'authoritative) :: bits 1) - ((value->bit (dns-message-truncated m) - 'not-truncated 'truncated) :: bits 1) - ((value->bit (dns-message-recursion-desired m) - 'no-recursion-desired 'recursion-desired) :: bits 1) - ((value->bit (dns-message-recursion-available m) - 'no-recursion-available 'recursion-available) :: bits 1) - (0 :: bits 3) - ((query-response-code->value (dns-message-response-code m)) :: bits 4) - ((length (dns-message-questions m)) :: bits 16) - ((length (dns-message-answers m)) :: bits 16) - ((length (dns-message-authorities m)) :: bits 16) - ((length (dns-message-additional m)) :: bits 16) - ((bit-string-append - (encode-section encode-question (dns-message-questions m)) - (encode-section encode-rr (dns-message-answers m)) - (encode-section encode-rr (dns-message-authorities m)) - (encode-section encode-rr (dns-message-additional m))) :: binary)))) - -(define (parse-section packet parser remaining-records input) - (let loop ((count remaining-records) - (input input)) - (cond - ((positive? count) - (let*-values (((record remainder) (parser packet input)) - ((records final-remainder) (loop (sub1 count) remainder))) - (values (cons record records) final-remainder))) - (else - (values '() input))))) - -(define (encode-section encoder records) - (cond - ((null? records) (bytes)) - ((null? (cdr records)) (encoder (car records))) - (else (bit-string-append (encoder (car records)) - (encode-section encoder (cdr records)))))) - -;; Domain-names use a strange "compressed" encoding. -;; We have to be careful not to get stuck in a pointer loop here. - -(define (parse-domain-name whole-packet input pointers-followed) - (bit-string-case input - - ([(= 3 :: bits 2) (offset :: bits 14) (rest :: binary)] - (if (member offset pointers-followed) - (error 'parse-domain-name "DNS compressed-pointer loop detected") - (let-values (((lhs rhs) (bit-string-split-at whole-packet (* 8 offset)))) - (let-values (((labels ignored-tail) - (parse-domain-name whole-packet rhs (cons offset pointers-followed)))) - (values labels rest))))) - - ([(= 0 :: bits 8) (rest :: binary)] - (values '() rest)) - - ([(= 0 :: bits 2) (len :: bits 6) (label :: binary bytes len) (rest :: binary)] - ;; TODO: validate labels: make sure they conform to the prescribed syntax - (let-values (((labels leftover) - (parse-domain-name whole-packet rest pointers-followed))) - (values (cons (bit-string->bytes label) labels) leftover))))) - -(define (parse-single-domain-name whole-packet input) - (let-values (((name remainder) (parse-domain-name whole-packet input '()))) - (if (bit-string-empty? remainder) - name - (error 'parse-single-domain-name - "Expected just the one name, but got some trailing junk")))) - -(define (extract-domain-names whole-packet input) - (if (bit-string-empty? input) - (let-values (((name remainder) (parse-domain-name whole-packet input '()))) - (cons name (extract-domain-names whole-packet remainder))) - '())) - -(define (encode-domain-name labels) - (cond - ((null? labels) (bytes 0)) - (else (bit-string-append (encode-label (car labels)) - (encode-domain-name (cdr labels)))))) - -(define (encode-label label) - (encode-pascal-string "Label" 64 label)) - -(define (encode-pascal-string string-kind length-limit s) - (let ((len (bytes-length s))) - (when (>= len length-limit) - (error 'encode-pascal-string "~s too long: ~v" string-kind s)) - (bytes-append (bytes len) s))) - -;; Character strings are pascal-style length-byte-prefixed strings. - -(define (extract-character-strings input) - (bit-string-case input - ([] - '()) - ([len (body :: binary bytes len) (rest :: binary)] - (cons (bit-string->bytes body) - (extract-character-strings rest))))) - -(define (encode-character-string bs) - (encode-pascal-string "Character-string" 256 bs)) - -;; -;; The question section is used to carry the "question" in most queries, -;; i.e., the parameters that define what is being asked. The section -;; contains QDCOUNT (usually 1) entries, each of the following format: -;; -;; 1 1 1 1 1 1 -;; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | | -;; / QNAME / -;; / / -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | QTYPE | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | QCLASS | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; - -(define (decode-question whole-packet input) - (let-values (((qname remainder) (parse-domain-name whole-packet input '()))) - (bit-string-case remainder - ([(qtype :: bits 16) - (qclass :: bits 16) - (tail :: binary)] - (values (question qname - (value->qtype qtype) - (value->qclass qclass)) - tail))))) - -(define (encode-question q) - (bit-string-append (encode-domain-name (question-name q)) - (bit-string ((qtype->value (question-type q)) :: bits 16) - ((qclass->value (question-class q)) :: bits 16)))) - -;; -;; All RRs have the same top level format shown below: -;; -;; 1 1 1 1 1 1 -;; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | | -;; / / -;; / NAME / -;; | | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | TYPE | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | CLASS | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | TTL | -;; | | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | RDLENGTH | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -;; / RDATA / -;; / / -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; - -(define (decode-rr whole-packet input) - (let-values (((name remainder) (parse-domain-name whole-packet input '()))) - (bit-string-case remainder - ([(type-number :: bits 16) - (class :: bits 16) - (ttl :: bits 32) - (rdlength :: bits 16) - (rdata :: binary bytes rdlength) - (tail :: binary)] - (let ((type (value->type type-number))) - (values (rr name - type - (value->class class) - ttl - (decode-rdata whole-packet type rdata)) - tail)))))) - -(define (decode-rdata whole-packet type rdata) - (case type - ((cname mb md mf mg mr ns ptr) (parse-single-domain-name whole-packet rdata)) - ((hinfo) (apply hinfo (extract-character-strings rdata))) - ((minfo) (apply minfo (extract-domain-names whole-packet rdata))) - ((mx) (bit-string-case rdata - ([(preference :: bits 16) (exchange :: binary)] - (mx preference (parse-single-domain-name whole-packet exchange))))) - ((null) (bit-string->bytes rdata)) - ((soa) (let*-values (((mname rdata1) (parse-domain-name whole-packet rdata '())) - ((rname rdata2) (parse-domain-name whole-packet rdata1 '()))) - (bit-string-case rdata2 - ([(serial :: bits 32) - (refresh :: bits 32) - (retry :: bits 32) - (expire :: bits 32) - (minimum :: bits 32)] - (soa mname rname serial refresh retry expire minimum))))) - ((txt) (extract-character-strings rdata)) - ((a) (bit-string-case rdata - ([a b c d] - (vector a b c d)))) - ((aaaa) (bit-string-case rdata - ([(ipv6-addr :: binary bits 128)] - (list->vector (bytes->list (bit-string->bytes ipv6-addr)))))) - ((wks) (bit-string-case rdata - ([a b c d protocol (bitmap :: binary)] - (wks (vector a b c d) protocol bitmap)))) - ((srv) (bit-string-case rdata - ([(priority :: bits 16) - (weight :: bits 16) - (port :: bits 16) - (target :: binary)] - (srv priority weight port (parse-single-domain-name whole-packet target))))) - (else (bit-string->bytes rdata)))) - -(define (encode-rr rr) - (let ((encoded-rdata (encode-rdata (rr-type rr) (rr-rdata rr)))) - (bit-string-append (encode-domain-name (rr-name rr)) - (bit-string ((type->value (rr-type rr)) :: bits 16) - ((class->value (rr-class rr)) :: bits 16) - ((rr-ttl rr) :: bits 32) - ((/ (bit-string-length encoded-rdata) 8) :: bits 16) - (encoded-rdata :: binary))))) - -(define (encode-rdata type rdata) - (case type - ((cname mb md mf mg mr ns ptr) (encode-domain-name rdata)) - ((hinfo) (bit-string-append (encode-character-string (hinfo-cpu rdata)) - (encode-character-string (hinfo-os rdata)))) - ((minfo) (bit-string-append (encode-character-string (minfo-rmailbx rdata)) - (encode-character-string (minfo-emailbx rdata)))) - ((mx) (bit-string ((mx-preference rdata) :: bits 16) - ((encode-domain-name (mx-exchange rdata)) :: binary))) - ((null) rdata) - ((soa) (bit-string-append (encode-domain-name (soa-mname rdata)) - (encode-domain-name (soa-rname rdata)) - (bit-string ((soa-serial rdata) :: bits 32) - ((soa-refresh rdata) :: bits 32) - ((soa-retry rdata) :: bits 32) - ((soa-expire rdata) :: bits 32) - ((soa-minimum rdata) :: bits 32)))) - ((txt) - ;; TODO: write and use bit-string-append* instead of using apply here - (foldl (lambda (s acc) (bit-string-append acc (encode-character-string s))) - (car rdata) - (cdr rdata))) - ((a) (match rdata ((vector a b c d) (bit-string a b c d)))) - ((aaaa) (bit-string ((list->bytes (vector->list rdata)) :: binary bits 128))) - ((wks) (match (wks-address rdata) - ((vector a b c d) - (bit-string a b c d (wks-protocol rdata) ((wks-bitmap rdata) :: binary))))) - ((srv) (bit-string ((srv-priority rdata) :: bits 16) - ((srv-weight rdata) :: bits 16) - ((srv-port rdata) :: bits 16) - ((encode-domain-name (srv-target rdata)) :: binary))) - (else rdata))) - -;;--------------------------------------------------------------------------- - -(define (make-dns-query questions - [recursion-desired 'no-recursion-desired]) - (dns-message (random 65536) - 'request - 'query - 'non-authoritative - 'not-truncated - recursion-desired - 'no-recursion-available - 'no-error - questions - '() - '() - '())) - -(define (make-dns-response query response-code answers authoritative - [recursion-available 'no-recursion-available] - [authorities '()] - [additional '()]) - (dns-message (dns-message-id query) - 'response - (dns-message-opcode query) - authoritative - 'not-truncated - (dns-message-recursion-desired query) - recursion-available - response-code - (dns-message-questions query) - answers - authorities - additional)) - -(define (next-timeout timeout) - (case timeout - ((3) 11) - ((11) 45) - ((45) #f))) - -(define *total-port-finding-attempts* 100) ;; TODO: eliminate arbitrary 100? - -(define (bind-to-random-port! s) - (let find-a-port ((remaining-tries *total-port-finding-attempts*)) - (if (zero? remaining-tries) - (error 'bind-to-random-port! "Could not find a free UDP port in ~v tries" - *total-port-finding-attempts*) - (let ((port-number (+ 1024 (random (- 65536 1024))))) - (with-handlers [(exn:fail:network? - (lambda (e) - ;; Bind failure. Port in use? - (find-a-port (- remaining-tries 1))))] - (udp-bind! s #f port-number)))))) - -(define (raw-dns-query query [servers '("127.0.0.1")]) - (let ((s (udp-open-socket #f #f))) - (bind-to-random-port! s) - ;; TODO: randomize ordering of servers in list. - (let search ((timeout 3) - (remaining-servers servers)) - (if (null? remaining-servers) - (let ((new-timeout (next-timeout timeout))) - (if new-timeout - (search new-timeout servers) - #f)) - (let ((server (car remaining-servers))) - (let ((server-hostname (if (string? server) server (car server))) - (server-port (if (string? server) 53 (cadr server)))) - ;;(write `(querying ,server-hostname ,server-port with timeout ,timeout)) (newline) - (udp-send-to s server-hostname server-port (dns-message->packet query)) - (let ((buffer (make-bytes 512))) ;; maximum DNS reply length - (let ((result (sync/timeout timeout (udp-receive!-evt s buffer)))) - ;; TODO: maybe receive only specifically from the queried IP address? - ;;(write `(response ,result)) (newline) - (if result - (let ((reply-length (car result))) - (packet->dns-message (sub-bit-string buffer 0 (* 8 reply-length)))) - (search timeout (cdr remaining-servers))))))))))) diff --git a/prototype/mapping.rkt b/prototype/mapping.rkt deleted file mode 100644 index 9189f16..0000000 --- a/prototype/mapping.rkt +++ /dev/null @@ -1,35 +0,0 @@ -#lang racket/base - -(provide define-mapping) - -(define-syntax check-defaults - (syntax-rules () - ((_ fn bn fd bd #:forward-default new-fd rest ...) - (check-defaults fn bn new-fd bd rest ...)) - ((_ fn bn fd bd #:backward-default new-bd rest ...) - (check-defaults fn bn fd new-bd rest ...)) - ((_ fn bn fd bd (lhs rhs) ...) - (begin - (define (fn l) - (case l - ((lhs) 'rhs) ... - (else (fd l)))) - (define (bn r) - (case r - ((rhs) 'lhs) ... - (else (bd r)))))))) - -(define (die-with-mapping-name n) - (lambda (v) - (raise (exn:fail:contract - (format "~v: Mapping not found for ~v" n v) - (current-continuation-marks))))) - -(define-syntax define-mapping - (syntax-rules () - ((_ forward-name backward-name rest ...) - (check-defaults forward-name - backward-name - (die-with-mapping-name 'forward-name) - (die-with-mapping-name 'backward-name) - rest ...)))) diff --git a/prototype/test-dns.rkt b/prototype/test-dns.rkt deleted file mode 100644 index 3e7b16c..0000000 --- a/prototype/test-dns.rkt +++ /dev/null @@ -1,248 +0,0 @@ -#lang racket/base - -(require "dns.rkt") - -;; Wed Jun 29 16:33:58 2011 (4e0b8c36): UDP: localhost sent 28 bytes: -;; 00000000: 66 3A 01 00 00 01 00 00 : 00 00 00 00 06 67 6F 6F f:...........goo -;; 00000010: 67 6C 65 03 63 6F 6D 00 : 00 FF 00 01 gle.com..... -;; 0000001C: - -(define (q-google-in-any) - (bytes #x66 #x3A #x01 #x00 #x00 #x01 #x00 #x00 - #x00 #x00 #x00 #x00 #x06 #x67 #x6F #x6F - #x67 #x6C #x65 #x03 #x63 #x6F #x6D #x00 - #x00 #xFF #x00 #x01)) - -;; Wed Jun 29 16:33:58 2011 (4e0b8c36): UDP: dslrouter.westell.com sent 494 bytes: -;; 00000000: 66 3A 81 80 00 01 00 0F : 00 00 00 07 06 67 6F 6F f:...........goo -;; 00000010: 67 6C 65 03 63 6F 6D 00 : 00 FF 00 01 C0 0C 00 10 gle.com......... -;; 00000020: 00 01 00 00 0C 2F 00 52 : 51 76 3D 73 70 66 31 20 ...../.RQv=spf1 -;; 00000030: 69 6E 63 6C 75 64 65 3A : 5F 6E 65 74 62 6C 6F 63 include:_netbloc -;; 00000040: 6B 73 2E 67 6F 6F 67 6C : 65 2E 63 6F 6D 20 69 70 ks.google.com ip -;; 00000050: 34 3A 32 31 36 2E 37 33 : 2E 39 33 2E 37 30 2F 33 4:216.73.93.70/3 -;; 00000060: 31 20 69 70 34 3A 32 31 : 36 2E 37 33 2E 39 33 2E 1 ip4:216.73.93. -;; 00000070: 37 32 2F 33 31 20 7E 61 : 6C 6C C0 0C 00 01 00 01 72/31 ~all...... -;; 00000080: 00 00 01 1D 00 04 4A 7D : E2 92 C0 0C 00 01 00 01 ......J}........ -;; 00000090: 00 00 01 1D 00 04 4A 7D : E2 94 C0 0C 00 01 00 01 ......J}........ -;; 000000A0: 00 00 01 1D 00 04 4A 7D : E2 91 C0 0C 00 01 00 01 ......J}........ -;; 000000B0: 00 00 01 1D 00 04 4A 7D : E2 93 C0 0C 00 01 00 01 ......J}........ -;; 000000C0: 00 00 01 1D 00 04 4A 7D : E2 90 C0 0C 00 02 00 01 ......J}........ -;; 000000D0: 00 03 A5 1D 00 06 03 6E : 73 32 C0 0C C0 0C 00 02 .......ns2...... -;; 000000E0: 00 01 00 03 A5 1D 00 06 : 03 6E 73 33 C0 0C C0 0C .........ns3.... -;; 000000F0: 00 02 00 01 00 03 A5 1D : 00 06 03 6E 73 31 C0 0C ...........ns1.. -;; 00000100: C0 0C 00 02 00 01 00 03 : A5 1D 00 06 03 6E 73 34 .............ns4 -;; 00000110: C0 0C C0 0C 00 0F 00 01 : 00 00 00 2A 00 11 00 14 ...........*.... -;; 00000120: 04 61 6C 74 31 05 61 73 : 70 6D 78 01 6C C0 0C C0 .alt1.aspmx.l... -;; 00000130: 0C 00 0F 00 01 00 00 00 : 2A 00 09 00 1E 04 61 6C ........*.....al -;; 00000140: 74 32 C1 25 C0 0C 00 0F : 00 01 00 00 00 2A 00 04 t2.%.........*.. -;; 00000150: 00 0A C1 25 C0 0C 00 0F : 00 01 00 00 00 2A 00 09 ...%.........*.. -;; 00000160: 00 28 04 61 6C 74 33 C1 : 25 C0 0C 00 0F 00 01 00 .(.alt3.%....... -;; 00000170: 00 00 2A 00 09 00 32 04 : 61 6C 74 34 C1 25 C0 E8 ..*...2.alt4.%.. -;; 00000180: 00 01 00 01 00 03 A2 CF : 00 04 D8 EF 24 0A C0 FA ............$... -;; 00000190: 00 01 00 01 00 03 A2 CF : 00 04 D8 EF 20 0A C1 0C ............ ... -;; 000001A0: 00 01 00 01 00 03 A2 CF : 00 04 D8 EF 26 0A C0 D6 ............&... -;; 000001B0: 00 01 00 01 00 03 A2 CF : 00 04 D8 EF 22 0A C1 3D ............"..= -;; 000001C0: 00 01 00 01 00 00 00 F0 : 00 04 4A 7D 27 1B C1 25 ..........J}'..% -;; 000001D0: 00 01 00 01 00 00 00 F6 : 00 04 4A 7D 73 1B C1 20 ..........J}s.. -;; 000001E0: 00 01 00 01 00 00 00 21 : 00 04 4A 7D 4D 1B .......!..J}M. -;; 000001EE: - -(define (a-google-in-any) - (bytes - #x66 #x3A #x81 #x80 #x00 #x01 #x00 #x0F #x00 #x00 #x00 #x07 #x06 #x67 #x6F #x6F - #x67 #x6C #x65 #x03 #x63 #x6F #x6D #x00 #x00 #xFF #x00 #x01 #xC0 #x0C #x00 #x10 - #x00 #x01 #x00 #x00 #x0C #x2F #x00 #x52 #x51 #x76 #x3D #x73 #x70 #x66 #x31 #x20 - #x69 #x6E #x63 #x6C #x75 #x64 #x65 #x3A #x5F #x6E #x65 #x74 #x62 #x6C #x6F #x63 - #x6B #x73 #x2E #x67 #x6F #x6F #x67 #x6C #x65 #x2E #x63 #x6F #x6D #x20 #x69 #x70 - #x34 #x3A #x32 #x31 #x36 #x2E #x37 #x33 #x2E #x39 #x33 #x2E #x37 #x30 #x2F #x33 - #x31 #x20 #x69 #x70 #x34 #x3A #x32 #x31 #x36 #x2E #x37 #x33 #x2E #x39 #x33 #x2E - #x37 #x32 #x2F #x33 #x31 #x20 #x7E #x61 #x6C #x6C #xC0 #x0C #x00 #x01 #x00 #x01 - #x00 #x00 #x01 #x1D #x00 #x04 #x4A #x7D #xE2 #x92 #xC0 #x0C #x00 #x01 #x00 #x01 - #x00 #x00 #x01 #x1D #x00 #x04 #x4A #x7D #xE2 #x94 #xC0 #x0C #x00 #x01 #x00 #x01 - #x00 #x00 #x01 #x1D #x00 #x04 #x4A #x7D #xE2 #x91 #xC0 #x0C #x00 #x01 #x00 #x01 - #x00 #x00 #x01 #x1D #x00 #x04 #x4A #x7D #xE2 #x93 #xC0 #x0C #x00 #x01 #x00 #x01 - #x00 #x00 #x01 #x1D #x00 #x04 #x4A #x7D #xE2 #x90 #xC0 #x0C #x00 #x02 #x00 #x01 - #x00 #x03 #xA5 #x1D #x00 #x06 #x03 #x6E #x73 #x32 #xC0 #x0C #xC0 #x0C #x00 #x02 - #x00 #x01 #x00 #x03 #xA5 #x1D #x00 #x06 #x03 #x6E #x73 #x33 #xC0 #x0C #xC0 #x0C - #x00 #x02 #x00 #x01 #x00 #x03 #xA5 #x1D #x00 #x06 #x03 #x6E #x73 #x31 #xC0 #x0C - #xC0 #x0C #x00 #x02 #x00 #x01 #x00 #x03 #xA5 #x1D #x00 #x06 #x03 #x6E #x73 #x34 - #xC0 #x0C #xC0 #x0C #x00 #x0F #x00 #x01 #x00 #x00 #x00 #x2A #x00 #x11 #x00 #x14 - #x04 #x61 #x6C #x74 #x31 #x05 #x61 #x73 #x70 #x6D #x78 #x01 #x6C #xC0 #x0C #xC0 - #x0C #x00 #x0F #x00 #x01 #x00 #x00 #x00 #x2A #x00 #x09 #x00 #x1E #x04 #x61 #x6C - #x74 #x32 #xC1 #x25 #xC0 #x0C #x00 #x0F #x00 #x01 #x00 #x00 #x00 #x2A #x00 #x04 - #x00 #x0A #xC1 #x25 #xC0 #x0C #x00 #x0F #x00 #x01 #x00 #x00 #x00 #x2A #x00 #x09 - #x00 #x28 #x04 #x61 #x6C #x74 #x33 #xC1 #x25 #xC0 #x0C #x00 #x0F #x00 #x01 #x00 - #x00 #x00 #x2A #x00 #x09 #x00 #x32 #x04 #x61 #x6C #x74 #x34 #xC1 #x25 #xC0 #xE8 - #x00 #x01 #x00 #x01 #x00 #x03 #xA2 #xCF #x00 #x04 #xD8 #xEF #x24 #x0A #xC0 #xFA - #x00 #x01 #x00 #x01 #x00 #x03 #xA2 #xCF #x00 #x04 #xD8 #xEF #x20 #x0A #xC1 #x0C - #x00 #x01 #x00 #x01 #x00 #x03 #xA2 #xCF #x00 #x04 #xD8 #xEF #x26 #x0A #xC0 #xD6 - #x00 #x01 #x00 #x01 #x00 #x03 #xA2 #xCF #x00 #x04 #xD8 #xEF #x22 #x0A #xC1 #x3D - #x00 #x01 #x00 #x01 #x00 #x00 #x00 #xF0 #x00 #x04 #x4A #x7D #x27 #x1B #xC1 #x25 - #x00 #x01 #x00 #x01 #x00 #x00 #x00 #xF6 #x00 #x04 #x4A #x7D #x73 #x1B #xC1 #x20 - #x00 #x01 #x00 #x01 #x00 #x00 #x00 #x21 #x00 #x04 #x4A #x7D #x4D #x1B)) - -(require racket/pretty) -(pretty-print (packet->dns-message (q-google-in-any))) -(pretty-print (packet->dns-message (a-google-in-any))) - -(pretty-print (dns-message->packet (packet->dns-message (a-google-in-any)))) - -;; Wed Jun 29 20:59:17 2011 (4e0bca65): UDP: localhost sent 28 bytes: -;; 00000000: 47 16 01 00 00 01 00 00 : 00 00 00 00 06 67 6F 6F G............goo -;; 00000010: 67 6C 65 03 63 6F 6D 00 : 00 1C 00 01 gle.com..... -;; 0000001C: -;; Wed Jun 29 20:59:17 2011 (4e0bca65): UDP: pass through succeeded -;; Wed Jun 29 20:59:17 2011 (4e0bca65): UDP: google-public-dns-a.google.com sent 78 bytes: -;; 00000000: 47 16 81 80 00 01 00 00 : 00 01 00 00 06 67 6F 6F G............goo -;; 00000010: 67 6C 65 03 63 6F 6D 00 : 00 1C 00 01 C0 0C 00 06 gle.com......... -;; 00000020: 00 01 00 00 02 52 00 26 : 03 6E 73 31 C0 0C 09 64 .....R.&.ns1...d -;; 00000030: 6E 73 2D 61 64 6D 69 6E : C0 0C 00 16 33 23 00 00 ns-admin....3#.. -;; 00000040: 1C 20 00 00 07 08 00 12 : 75 00 00 00 01 2C . ......u...., -;; 0000004E: - -(pretty-print - (packet->dns-message - (bytes - #x47 #x16 #x01 #x00 #x00 #x01 #x00 #x00 #x00 #x00 #x00 #x00 #x06 #x67 #x6F #x6F - #x67 #x6C #x65 #x03 #x63 #x6F #x6D #x00 #x00 #x1C #x00 #x01))) - -(pretty-print - (packet->dns-message - (bytes - #x47 #x16 #x81 #x80 #x00 #x01 #x00 #x00 #x00 #x01 #x00 #x00 #x06 #x67 #x6F #x6F - #x67 #x6C #x65 #x03 #x63 #x6F #x6D #x00 #x00 #x1C #x00 #x01 #xC0 #x0C #x00 #x06 - #x00 #x01 #x00 #x00 #x02 #x52 #x00 #x26 #x03 #x6E #x73 #x31 #xC0 #x0C #x09 #x64 - #x6E #x73 #x2D #x61 #x64 #x6D #x69 #x6E #xC0 #x0C #x00 #x16 #x33 #x23 #x00 #x00 - #x1C #x20 #x00 #x00 #x07 #x08 #x00 #x12 #x75 #x00 #x00 #x00 #x01 #x2C))) - -;; Wed Jun 29 21:05:03 2011 (4e0bcbbf): UDP: localhost sent 32 bytes: -;; 00000000: 12 70 01 00 00 01 00 00 : 00 00 00 00 03 77 77 77 .p...........www -;; 00000010: 06 67 6F 6F 67 6C 65 03 : 63 6F 6D 00 00 1C 00 01 .google.com..... -;; 00000020: -;; Wed Jun 29 21:05:03 2011 (4e0bcbbf): UDP: pass through succeeded -;; Wed Jun 29 21:05:03 2011 (4e0bcbbf): UDP: ns1.google.com sent 52 bytes: -;; 00000000: 12 70 85 00 00 01 00 01 : 00 00 00 00 03 77 77 77 .p...........www -;; 00000010: 06 67 6F 6F 67 6C 65 03 : 63 6F 6D 00 00 1C 00 01 .google.com..... -;; 00000020: C0 0C 00 05 00 01 00 09 : 3A 80 00 08 03 77 77 77 ........:....www -;; 00000030: 01 6C C0 10 : .l.. -;; 00000034: - -(pretty-print - (packet->dns-message - (bytes - #x12 #x70 #x01 #x00 #x00 #x01 #x00 #x00 #x00 #x00 #x00 #x00 #x03 #x77 #x77 #x77 - #x06 #x67 #x6F #x6F #x67 #x6C #x65 #x03 #x63 #x6F #x6D #x00 #x00 #x1C #x00 #x01))) - -(pretty-print - (packet->dns-message - (bytes - #x12 #x70 #x85 #x00 #x00 #x01 #x00 #x01 #x00 #x00 #x00 #x00 #x03 #x77 #x77 #x77 - #x06 #x67 #x6F #x6F #x67 #x6C #x65 #x03 #x63 #x6F #x6D #x00 #x00 #x1C #x00 #x01 - #xC0 #x0C #x00 #x05 #x00 #x01 #x00 #x09 #x3A #x80 #x00 #x08 #x03 #x77 #x77 #x77 - #x01 #x6C #xC0 #x10))) - -;; Wed Jun 29 21:07:46 2011 (4e0bcc62): UDP: ns1.google.com sent 82 bytes: -;; 00000000: 23 79 85 00 00 01 00 02 : 00 00 00 00 04 69 70 76 #y...........ipv -;; 00000010: 36 06 67 6F 6F 67 6C 65 : 03 63 6F 6D 00 00 1C 00 6.google.com.... -;; 00000020: 01 C0 0C 00 05 00 01 00 : 09 3A 80 00 09 04 69 70 .........:....ip -;; 00000030: 76 36 01 6C C0 11 C0 2D : 00 1C 00 01 00 00 01 2C v6.l...-......., -;; 00000040: 00 10 20 01 48 60 80 0F : 00 00 00 00 00 00 00 00 .. .H`.......... -;; 00000050: 00 68 : .h -;; 00000052: - -(pretty-print - (packet->dns-message - (bytes - #x23 #x79 #x85 #x00 #x00 #x01 #x00 #x02 #x00 #x00 #x00 #x00 #x04 #x69 #x70 #x76 - #x36 #x06 #x67 #x6F #x6F #x67 #x6C #x65 #x03 #x63 #x6F #x6D #x00 #x00 #x1C #x00 - #x01 #xC0 #x0C #x00 #x05 #x00 #x01 #x00 #x09 #x3A #x80 #x00 #x09 #x04 #x69 #x70 - #x76 #x36 #x01 #x6C #xC0 #x11 #xC0 #x2D #x00 #x1C #x00 #x01 #x00 #x00 #x01 #x2C - #x00 #x10 #x20 #x01 #x48 #x60 #x80 #x0F #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 - #x00 #x68))) - -(pretty-print - (dns-message->packet - (packet->dns-message - (bytes - #x23 #x79 #x85 #x00 #x00 #x01 #x00 #x02 #x00 #x00 #x00 #x00 #x04 #x69 #x70 #x76 - #x36 #x06 #x67 #x6F #x6F #x67 #x6C #x65 #x03 #x63 #x6F #x6D #x00 #x00 #x1C #x00 - #x01 #xC0 #x0C #x00 #x05 #x00 #x01 #x00 #x09 #x3A #x80 #x00 #x09 #x04 #x69 #x70 - #x76 #x36 #x01 #x6C #xC0 #x11 #xC0 #x2D #x00 #x1C #x00 #x01 #x00 #x00 #x01 #x2C - #x00 #x10 #x20 #x01 #x48 #x60 #x80 #x0F #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x00 - #x00 #x68)))) - -;; Thu Jun 30 15:12:45 2011 (4e0ccaad): UDP: asgard.ccs.neu.edu sent 486 bytes: -;; 00000000: 13 CA 81 80 00 01 00 05 : 00 04 00 09 0C 5F 78 6D ............._xm -;; 00000010: 70 70 2D 73 65 72 76 65 : 72 04 5F 74 63 70 06 67 pp-server._tcp.g -;; 00000020: 6F 6F 67 6C 65 03 63 6F : 6D 00 00 21 00 01 C0 0C oogle.com..!.... -;; 00000030: 00 21 00 01 00 00 03 72 : 00 21 00 14 00 00 14 95 .!.....r.!...... -;; 00000040: 0C 78 6D 70 70 2D 73 65 : 72 76 65 72 34 01 6C 06 .xmpp-server4.l. -;; 00000050: 67 6F 6F 67 6C 65 03 63 : 6F 6D 00 C0 0C 00 21 00 google.com....!. -;; 00000060: 01 00 00 03 72 00 20 00 : 05 00 00 14 95 0B 78 6D ....r. .......xm -;; 00000070: 70 70 2D 73 65 72 76 65 : 72 01 6C 06 67 6F 6F 67 pp-server.l.goog -;; 00000080: 6C 65 03 63 6F 6D 00 C0 : 0C 00 21 00 01 00 00 03 le.com....!..... -;; 00000090: 72 00 21 00 14 00 00 14 : 95 0C 78 6D 70 70 2D 73 r.!.......xmpp-s -;; 000000A0: 65 72 76 65 72 31 01 6C : 06 67 6F 6F 67 6C 65 03 erver1.l.google. -;; 000000B0: 63 6F 6D 00 C0 0C 00 21 : 00 01 00 00 03 72 00 21 com....!.....r.! -;; 000000C0: 00 14 00 00 14 95 0C 78 : 6D 70 70 2D 73 65 72 76 .......xmpp-serv -;; 000000D0: 65 72 32 01 6C 06 67 6F : 6F 67 6C 65 03 63 6F 6D er2.l.google.com -;; 000000E0: 00 C0 0C 00 21 00 01 00 : 00 03 72 00 21 00 14 00 ....!.....r.!... -;; 000000F0: 00 14 95 0C 78 6D 70 70 : 2D 73 65 72 76 65 72 33 ....xmpp-server3 -;; 00000100: 01 6C 06 67 6F 6F 67 6C : 65 03 63 6F 6D 00 C1 02 .l.google.com... -;; 00000110: 00 02 00 01 00 01 54 24 : 00 06 03 6E 73 33 C1 02 ......T$...ns3.. -;; 00000120: C1 02 00 02 00 01 00 01 : 54 24 00 06 03 6E 73 34 ........T$...ns4 -;; 00000130: C1 02 C1 02 00 02 00 01 : 00 01 54 24 00 06 03 6E ..........T$...n -;; 00000140: 73 32 C1 02 C1 02 00 02 : 00 01 00 01 54 24 00 06 s2..........T$.. -;; 00000150: 03 6E 73 31 C1 02 C0 6D : 00 01 00 01 00 00 01 1A .ns1...m........ -;; 00000160: 00 04 4A 7D 99 7D C0 99 : 00 01 00 01 00 00 06 F6 ..J}.}.......... -;; 00000170: 00 04 4A 7D 35 7D C0 C6 : 00 01 00 01 00 00 06 F6 ..J}5}.......... -;; 00000180: 00 04 4A 7D 2F 7D C0 F3 : 00 01 00 01 00 00 06 F6 ..J}/}.......... -;; 00000190: 00 04 4A 7D 2D 7D C0 40 : 00 01 00 01 00 00 06 F6 ..J}-}.@........ -;; 000001A0: 00 04 4A 7D 2D 7D C1 50 : 00 01 00 01 00 00 0A B1 ..J}-}.P........ -;; 000001B0: 00 04 D8 EF 20 0A C1 3E : 00 01 00 01 00 00 0A B1 .... ..>........ -;; 000001C0: 00 04 D8 EF 22 0A C1 1A : 00 01 00 01 00 00 0A B1 ...."........... -;; 000001D0: 00 04 D8 EF 24 0A C1 2C : 00 01 00 01 00 00 0A B1 ....$..,........ -;; 000001E0: 00 04 D8 EF 26 0A : ....&. -;; 000001E6: - -;; ANSWER SECTION: -;;_xmpp-server._tcp.google.com. 900 IN SRV 5 0 5269 xmpp-server.l.google.com. -;;_xmpp-server._tcp.google.com. 900 IN SRV 20 0 5269 xmpp-server1.l.google.com. -;;_xmpp-server._tcp.google.com. 900 IN SRV 20 0 5269 xmpp-server2.l.google.com. -;;_xmpp-server._tcp.google.com. 900 IN SRV 20 0 5269 xmpp-server3.l.google.com. -;;_xmpp-server._tcp.google.com. 900 IN SRV 20 0 5269 xmpp-server4.l.google.com. - -(pretty-print - (packet->dns-message - (bytes - #x13 #xCA #x81 #x80 #x00 #x01 #x00 #x05 #x00 #x04 #x00 #x09 #x0C #x5F #x78 #x6D - #x70 #x70 #x2D #x73 #x65 #x72 #x76 #x65 #x72 #x04 #x5F #x74 #x63 #x70 #x06 #x67 - #x6F #x6F #x67 #x6C #x65 #x03 #x63 #x6F #x6D #x00 #x00 #x21 #x00 #x01 #xC0 #x0C - #x00 #x21 #x00 #x01 #x00 #x00 #x03 #x72 #x00 #x21 #x00 #x14 #x00 #x00 #x14 #x95 - #x0C #x78 #x6D #x70 #x70 #x2D #x73 #x65 #x72 #x76 #x65 #x72 #x34 #x01 #x6C #x06 - #x67 #x6F #x6F #x67 #x6C #x65 #x03 #x63 #x6F #x6D #x00 #xC0 #x0C #x00 #x21 #x00 - #x01 #x00 #x00 #x03 #x72 #x00 #x20 #x00 #x05 #x00 #x00 #x14 #x95 #x0B #x78 #x6D - #x70 #x70 #x2D #x73 #x65 #x72 #x76 #x65 #x72 #x01 #x6C #x06 #x67 #x6F #x6F #x67 - #x6C #x65 #x03 #x63 #x6F #x6D #x00 #xC0 #x0C #x00 #x21 #x00 #x01 #x00 #x00 #x03 - #x72 #x00 #x21 #x00 #x14 #x00 #x00 #x14 #x95 #x0C #x78 #x6D #x70 #x70 #x2D #x73 - #x65 #x72 #x76 #x65 #x72 #x31 #x01 #x6C #x06 #x67 #x6F #x6F #x67 #x6C #x65 #x03 - #x63 #x6F #x6D #x00 #xC0 #x0C #x00 #x21 #x00 #x01 #x00 #x00 #x03 #x72 #x00 #x21 - #x00 #x14 #x00 #x00 #x14 #x95 #x0C #x78 #x6D #x70 #x70 #x2D #x73 #x65 #x72 #x76 - #x65 #x72 #x32 #x01 #x6C #x06 #x67 #x6F #x6F #x67 #x6C #x65 #x03 #x63 #x6F #x6D - #x00 #xC0 #x0C #x00 #x21 #x00 #x01 #x00 #x00 #x03 #x72 #x00 #x21 #x00 #x14 #x00 - #x00 #x14 #x95 #x0C #x78 #x6D #x70 #x70 #x2D #x73 #x65 #x72 #x76 #x65 #x72 #x33 - #x01 #x6C #x06 #x67 #x6F #x6F #x67 #x6C #x65 #x03 #x63 #x6F #x6D #x00 #xC1 #x02 - #x00 #x02 #x00 #x01 #x00 #x01 #x54 #x24 #x00 #x06 #x03 #x6E #x73 #x33 #xC1 #x02 - #xC1 #x02 #x00 #x02 #x00 #x01 #x00 #x01 #x54 #x24 #x00 #x06 #x03 #x6E #x73 #x34 - #xC1 #x02 #xC1 #x02 #x00 #x02 #x00 #x01 #x00 #x01 #x54 #x24 #x00 #x06 #x03 #x6E - #x73 #x32 #xC1 #x02 #xC1 #x02 #x00 #x02 #x00 #x01 #x00 #x01 #x54 #x24 #x00 #x06 - #x03 #x6E #x73 #x31 #xC1 #x02 #xC0 #x6D #x00 #x01 #x00 #x01 #x00 #x00 #x01 #x1A - #x00 #x04 #x4A #x7D #x99 #x7D #xC0 #x99 #x00 #x01 #x00 #x01 #x00 #x00 #x06 #xF6 - #x00 #x04 #x4A #x7D #x35 #x7D #xC0 #xC6 #x00 #x01 #x00 #x01 #x00 #x00 #x06 #xF6 - #x00 #x04 #x4A #x7D #x2F #x7D #xC0 #xF3 #x00 #x01 #x00 #x01 #x00 #x00 #x06 #xF6 - #x00 #x04 #x4A #x7D #x2D #x7D #xC0 #x40 #x00 #x01 #x00 #x01 #x00 #x00 #x06 #xF6 - #x00 #x04 #x4A #x7D #x2D #x7D #xC1 #x50 #x00 #x01 #x00 #x01 #x00 #x00 #x0A #xB1 - #x00 #x04 #xD8 #xEF #x20 #x0A #xC1 #x3E #x00 #x01 #x00 #x01 #x00 #x00 #x0A #xB1 - #x00 #x04 #xD8 #xEF #x22 #x0A #xC1 #x1A #x00 #x01 #x00 #x01 #x00 #x00 #x0A #xB1 - #x00 #x04 #xD8 #xEF #x24 #x0A #xC1 #x2C #x00 #x01 #x00 #x01 #x00 #x00 #x0A #xB1 - #x00 #x04 #xD8 #xEF #x26 #x0A))) diff --git a/prototype/test-mapping.rkt b/prototype/test-mapping.rkt deleted file mode 100644 index 6f31f1e..0000000 --- a/prototype/test-mapping.rkt +++ /dev/null @@ -1,25 +0,0 @@ -#lang racket/base - -(require "mapping.rkt") -(require rackunit) - -(define-mapping a->b b->a - (a b)) - -(check-equal? (a->b 'a) 'b) -(check-equal? (b->a 'b) 'a) -(check-exn exn:fail:contract? (lambda () (a->b 123))) -(check-exn exn:fail:contract? (lambda () (a->b 'b))) -(check-exn exn:fail:contract? (lambda () (b->a 123))) -(check-exn exn:fail:contract? (lambda () (b->a 'a))) - -(define-mapping c->d d->c - #:forward-default (lambda (x) 'default-d) - #:backward-default (lambda (x) 'default-c) - (c 123) - (e 234)) - -(check-equal? (c->d 'c) 123) -(check-equal? (d->c 234) 'e) -(check-equal? (c->d 'other) 'default-d) -(check-equal? (d->c '235) 'default-c) diff --git a/simple-udp-service.rkt b/simple-udp-service.rkt deleted file mode 100644 index 09fe0e2..0000000 --- a/simple-udp-service.rkt +++ /dev/null @@ -1,97 +0,0 @@ -#lang racket/base - -;; Simple imperative UDP server harness. - -(require racket/match) -(require racket/udp) -(require (only-in srfi/1 append-reverse)) -(require racket-typed-matrix/support/dump-bytes) - -(provide (struct-out udp-packet) - message-handlers - start-udp-service) - -;; A UdpPacket is a (udp-packet Bytes String Uint16), and represents -;; either a received UDP packet and the source of the packet, or a UDP -;; packet ready to be sent along with the address to which it should -;; be sent. -(struct udp-packet (body host port) #:prefab) - -;; TODO: Should packet->message be permitted to examine (or possibly -;; even transform!) the ServerState? - -;; A Handler is a Message ServerState -> ListOf ServerState. - -(define-syntax message-handlers - (syntax-rules () - ((_ old-state-var (pattern body ...) ...) - (list (cons (match-lambda (pattern #t) (_ #f)) - (lambda (v old-state-var) - (match v - (pattern body ...)))) - ...)))) - -;; Starts a generic request/reply UDP server on the given port. -(define (start-udp-service - port-number ;; Uint16 - packet->message ;; UdpPacket -> Message - ;;-------------------------------------------------- - outbound-message? ;; Message -> Boolean - message->packet ;; Message -> UdpPacket - ;;-------------------------------------------------- - message-handlers ;; ListOf Boolean, Handler>> - default-handler ;; Handler - initial-state ;; ServerState - #:packet-size-limit - [packet-size-limit 65536]) - (define s (udp-open-socket #f #f)) ;; the server socket - (udp-bind! s #f port-number) ;; bind it to the port we were given - - (set! message-handlers ;; TEMPORARY while I figure out I/O - (cons (cons outbound-message? - (lambda (message state) - (define p (message->packet message)) - (match-define (udp-packet body host port) p) - (printf "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~n~v~n" body) - (dump-bytes! body (bytes-length body)) - (flush-output) - (udp-send-to s host port body) - (values '() state))) - message-handlers)) - - (define (dispatch-messages messages next-messages-rev old-state) - (if (null? messages) - (check-for-io (reverse next-messages-rev) old-state) - (let ((message (car messages))) - (define-values (new-messages new-state) - (let search ((handlers message-handlers)) - (cond - [(null? handlers) (default-handler message old-state)] - [((caar handlers) message) ((cdar handlers) message old-state)] - [else (search (cdr handlers))]))) - (dispatch-messages (cdr messages) - (append-reverse new-messages next-messages-rev) - new-state)))) - - (define (check-for-io pending-messages old-state) - (define buffer (make-bytes packet-size-limit)) - (define new-messages - (sync (handle-evt (udp-receive!-evt s buffer) - (match-lambda - [(list packet-length source-hostname source-port) - (define packet (subbytes buffer 0 packet-length)) - (printf ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>~n~v~n" packet) - (dump-bytes! buffer packet-length) - (flush-output) - - (define packet-and-source - (udp-packet packet source-hostname source-port)) - (define message (packet->message packet-and-source)) - (list message)])) - (if (null? pending-messages) - never-evt ;; Nothing waiting to be done, don't wake up until sth external arrives - (handle-evt (system-idle-evt) - (lambda (dummy) '()))))) - (dispatch-messages (append new-messages pending-messages) '() old-state)) - - (check-for-io '() initial-state)) diff --git a/simplified-driver.rkt b/simplified-driver.rkt deleted file mode 100644 index ca679f3..0000000 --- a/simplified-driver.rkt +++ /dev/null @@ -1,156 +0,0 @@ -#lang racket/base - -;; DNS server using simple-udp-service.rkt. - -(require racket/unit) -(require racket/match) -(require racket/set) -(require racket/bool) -(require racket-bitsyntax) -(require "api.rkt") -(require "codec.rkt") -(require "zonedb.rkt") -(require "resolver.rkt") -(require "simple-udp-service.rkt") - -;; Instantiated with a SOA record for the zone it is serving as well -;; as a zone's worth of DNS data which is used to answer queries -;; authoritatively. Never caches information, never performs recursive -;; queries. - -;; Rules: - -;; - Answers authoritative NXDOMAIN answers for queries falling within -;; its zone. (This is the only responder entitled to answer NXDOMAIN!) -;; - Answers with referrals for queries falling in subzones. It -;; determines subzones based on the RRs it is configured with at -;; startup. - -(struct bad-dns-packet (detail host port reason) #:prefab) -(struct dns-request (message host port) #:prefab) -(struct dns-reply (message host port) #:prefab) - -;; start-server : UInt16 RR ListOf -> Void -;; Starts a server that will answer questions received on the given -;; UDP port based on the RRs it is given and the zone origin specified -;; in the soa-rr given. -(require racket/pretty) -(define (start-server port-number soa-rr rrs) - ;; Compile the zone hash table - (define zone (compile-zone-db (cons soa-rr rrs))) - (pretty-print zone) - - (start-udp-service - port-number - udp-packet->dns-message - dns-reply? - dns-reply->udp-packet - (message-handlers old-state - [(? bad-dns-packet? p) - (pretty-print p) - (values '() old-state)] - [(? dns-request? r) - (values (handle-request soa-rr zone r) old-state)]) - (lambda (unhandled state) - (error 'dns-server "Unhandled packet ~v" unhandled)) - #f - #:packet-size-limit 512)) - -(define (udp-packet->dns-message packet) - (match-define (udp-packet body host port) packet) - (with-handlers ((exn:fail? (lambda (e) (bad-dns-packet body host port 'unparseable)))) - (define message (packet->dns-message body)) - (case (dns-message-direction message) - ((request) (dns-request message host port)) - ((response) (bad-dns-packet message host port 'unexpected-dns-response))))) - -;; TODO: dns-reply->udp-packet may fail! The server may supply some -;; value that isn't a proper DNSMessage. In that case we might like to -;; not send a UDP packet, but instead send out a bad-dns-packet local -;; message for logging etc. (Glossing over the issue of identifying -;; the direction of the message for now.) -;; -;; Once we move to pluggable external-event-sources/relays this will -;; go away: they'll be handlers like anything else, that just happen -;; to have a side effect in some containing (or if not containing, at -;; least *in-scope*) network. - -(define (dns-reply->udp-packet r) - (match-define (dns-reply message host port) r) - (udp-packet (dns-message->packet message) host port)) - -(define (first-only xs) - (if (null? xs) - xs - (cons (car xs) '()))) - -(define (handle-request soa-rr zone request) - (match-define (dns-request request-message request-host request-port) request) - - (define (make-reply name send-name-error? answers authorities additional) - (dns-message (dns-message-id request-message) - 'response - 'query - (if (in-bailiwick? name (rr-name soa-rr)) 'authoritative 'non-authoritative) - 'not-truncated - (dns-message-recursion-desired request-message) - 'no-recursion-available - (if send-name-error? 'name-error 'no-error) - (dns-message-questions request-message) - (rr-set->list answers) - (rr-set->list authorities) - (rr-set->list additional))) - - (define (answer-question q make-reply) - ;; Notice that we claim to be authoritative for our configured - ;; zone. If we ever answer name-error, that means there are no RRs - ;; *at all* for the queried name. If there are RRs for the queried - ;; name, but they happen not to be the ones asked for, name-error - ;; must *not* be returned: instead, a normal no-error reply is - ;; sent with an empty answer section. - ;; - ;; If we wanted to support caching of negative replies, we'd - ;; follow the guidelines in section 4.3.4 "Negative response - ;; caching" of RFC1034, adding our zone SOA with an appropriate - ;; TTL to the additional section of the reply. - ;; - ;; TODO: We support returning out-of-bailiwick records (glue) - ;; here. Reexamine the rules for doing so. - (match-define (question qname qtype qclass #f) q) - - (define (expand-cnames worklist ans) - (match worklist - ['() - (match-define (complete-answer ns us ds) ans) - (make-reply qname #f ns us ds)] - [(cons next-cname rest) - (define a (resolve-from-zone (question next-cname qtype qclass q) zone soa-rr (set))) - (incorporate-answer a rest ans)])) - - (define (incorporate-answer this-answer worklist ans) - (match this-answer - [(partial-answer new-info more-cnames) - (expand-cnames (append worklist more-cnames) - (merge-answers new-info ans))] - [(? complete-answer?) - (expand-cnames worklist - (merge-answers this-answer ans))] - [_ ;; #f or a referral - (expand-cnames worklist ans)])) - - (match (resolve-from-zone q zone soa-rr (set)) - [#f ;; Signal name-error/NXDOMAIN - (make-reply qname #t (set) (set) (set))] - [(referral _ ns-rrs additional) - (make-reply qname #f ns-rrs (set soa-rr) additional)] - [this-answer - (incorporate-answer this-answer '() (empty-complete-answer))])) - - ;; TODO: check opcode and direction in request - ;; TODO: think again about multiple questions in one packet - (map (lambda (q) - (dns-reply (answer-question q make-reply) request-host request-port)) - (first-only (dns-message-questions request-message)))) - -(require "test-rrs.rkt") -(start-server (test-port-number) test-soa-rr test-rrs) diff --git a/stress.rkt b/stress.rkt deleted file mode 100644 index 22dd9c4..0000000 --- a/stress.rkt +++ /dev/null @@ -1,75 +0,0 @@ -#lang racket/base - -;; Simple stress-tester and performance measurement tool for DNS -;; implementations. - -(require racket/udp) -(require racket/set) -(require racket-bitsyntax) -(require "api.rkt") -(require "codec.rkt") -(require "test-rrs.rkt") - -(require racket/pretty) - -(define latencies (make-vector 200 0)) -(define latency-pos 0) -(define (record-latency-ms! ms) - (vector-set! latencies latency-pos ms) - (set! latency-pos (modulo (+ latency-pos 1) (vector-length latencies))) - (when (zero? latency-pos) - (for-each display (list ";; Mean latency "(/ (for/fold - ((sum 0)) - ((i latencies)) - (+ sum i)) - (vector-length latencies))"ms\n")))) - -(define (stress hostname port-number count rate) - (define s (udp-open-socket #f #f)) - - (define start-time (current-inexact-milliseconds)) - (let loop ((remaining count)) - (define request-message (dns-message (random 65536) - 'request - 'query - 'non-authoritative - 'not-truncated - 'recursion-desired - 'no-recursion-available - 'no-error - (list (question (domain '(#"www" #"google" #"com")) - 'a - 'in - #f)) - '() - '() - '())) - - (define now (current-inexact-milliseconds)) - (define sent-count (- count remaining)) - (define delta-ms (- now start-time)) - (define current-rate (/ sent-count (/ delta-ms 1000.0))) - - (when (> current-rate rate) - (define target-delta-sec (/ sent-count rate)) - (sleep (- target-delta-sec (/ delta-ms 1000)))) - - (when (zero? (modulo sent-count rate)) - (for-each display (list ";; Sent "sent-count" at target "rate"Hz, actual " - current-rate"Hz, in "delta-ms"ms\n"))) - - (when (positive? remaining) - (define sent-time (current-inexact-milliseconds)) - (udp-send-to s hostname port-number (dns-message->packet request-message)) - - (define buffer (make-bytes 512)) - (define-values (packet-length source-hostname source-port) - (udp-receive! s buffer)) - (define received-time (current-inexact-milliseconds)) - (define reply (packet->dns-message (sub-bit-string buffer 0 (* 8 packet-length)))) - - ;;(pretty-print reply) - (record-latency-ms! (- received-time sent-time)) - (loop (- remaining 1))))) - -(stress "localhost" (test-port-number) 100000 500)