chiark / gitweb /
WIP dns transport packets etc.
[secnet.git] / dns-transp-server.c
1 /* Module for (ab)using DNS as a transport */
2
3 /* This provides two new kinds of closure, both of type comm.
4  *  dns-transport-server
5  *    which takes an underlying udp comm
6  *    and which never supports lookup by address
7  *  dns-transport-client
8  */
9
10
11 /*
12  * Query format: create assoc:
13  *   32 bits       clientnonce
14  *    1 bit set    this is a create assoc query
15  *   10 bits       offset of this data fragment in packet
16  *    1 bit        is this the last fragment ?
17  *    remainder    data packet fragment
18  * data packet sequence number is always implicitly zero
19  *
20  * Query format: submit:
21  *   32 bits       associd
22  *    1 bit clear  this is not a create assoc query
23  *   16 bits       data packet sequence number
24  *   10 bits       offset of this data fragment in packet
25  *    1 bit        is this the last fragment
26  *    remainder    data packet fragment
27  *
28  * Query format: fetch:
29  *   32 bits       associd
30  *    1 bit clear  this is not a create assoc query
31  *   16 bits       client query distinguisher (for defeating dns cache)
32  *
33  * Response format:
34  * [ 32 bits       associd  - only for responses to create assoc ]
35  *    4 bits       log_2( number of bytes of outstanding data on server)
36  *   10 bits       offset of this data fragment in packet
37  *    1 bit        is this the last fragment ?
38  *    remainder    data packet fragment
39  */
40
41 /*
42  * Query bitstring, from above, is encoded as follows:
43  *   1. 
44  *    . append our server's domain
45  * Max DNS domain is 255 bytes.
46  * Max UDP packet is 512 bytes.
47  * If our domain is     .s.chiark.net.     (12 bytes)
48  * then we have 241 bytes of payload left.
49  * We need at least 4 subdomains to avoid blowing the 63-byte limit
50  * So that means we need 3 more dots, so 238 chars.
51  * At 5 bits per char that's 1190 bits.  Minus our submit
52  * header (1+32+16+10+1 = 60 bits) that's 1130 bits or 141.25 bytes.
53  */
54
55 struct expires {
56     struct expires *next;
57     struct timeval expires;
58 };
59
60 struct dedupe {
61     uint8_t *qsubdomhash; /* of length dns_server->hash->len */
62     struct expires expires;
63     int responselen;   /* -1 if we are holding this query */
64     uint8_t *response; /*  0 if we are holding this query */
65 };
66
67 struct holding {
68     struct holding *next, *back;
69     struct expires expires;
70     int qsubdomlen; /* in octets */
71     uint8_t *qsubdom; /* in dns format ready for packet */
72     struct dedupe *dedupe;
73 };
74
75 struct assoc {
76     uint32_t associd;
77     struct expires expires; /* clock is running once the clientinit expires */
78     /* table of incoming partial messages */
79     int incoming_used, incoming_allocd;
80     uint32_t incoming_firstseq;
81     struct incomingmsg *incoming;
82     /* table of outgoing messages */
83     int outgoing_used, outgoing_allocd;
84     uint32_t outgoingmsg *outgoing;
85     /* dedupe table */
86     HASHTABLE(struct dedupe) dedupe;
87     /* holding responses */
88     SLIST(struct holding) holding;
89 };
90
91 struct clientinit {
92     struct sockaddr_in clientaddr;
93     uint32_t clientnonce;
94     struct expires expires;
95     struct assoc *assoc;
96 };
97
98 struct dns_server {
99     closure_t cl;
100     struct comm_if ops;
101     struct comm_if *port;
102     struct hash_if *hash; /* used for dedupe */
103     HASHTABLE(struct clientinit) clientinits;
104     HASHTABLE(struct assoc) assocs;
105 };
106
107 /*
108  * Incoming packet
109  *
110  * 1. decode dns packet, check it is for us, etc.
111  * 2. hash qsubdom
112  * 3. check qsubdomhash in dedupe
113  *    if found, send response (or discard, if we are holding), done.
114  * 4a. create assoc packet
115  *    look up {clientaddr,clientnonce} in clientinit
116  *    if not then create an assoc
117  */
118
119
120
121
122 void incoming_packet(const uint8_t pkt, int len) {
123     if (len < DNS_HDRLEN)
124         return badpkt("shorter than dns header");
125     
126     uint16_t id =