3 * Copyright (c) 2018 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * Simple Service Registration Protocol Client
19 * This is intended for the constrained node solution for SRP. It's intended to be flexible and
20 * understandable while linking in the minimum possible support code to reduce code size. It does
21 * no mallocs, does not put anything big on the stack, and doesn't require an event loop.
25 #include <arpa/inet.h>
31 #include "srp-crypto.h"
34 dns_response_callback(dns_transaction_t
*txn
)
39 main(int argc
, char **argv
)
41 const char *host_name
= "thread-demo";
42 const char *zone_name
= "default.service.arpa";
43 const char *host_fqdn
= "thread-demo.default.service.arpa";
44 const char *service_type
= "_ipps._tcp";
45 const char *a_record
= "127.0.0.1";
46 const char *aaaa_record
= "::1";
47 const char *txt_record
= "0";
48 const char *anycast_address
= "127.0.0.1";
49 // const char *anycast_address = "73.186.137.119"; // cer.fugue.com
50 const char *keyfile_name
= "srp-simple.key";
53 dns_wire_t message
, response
;
55 static dns_transaction_t txn
;
56 dns_towire_state_t
*towire
= &txn
.towire
;
57 dns_name_pointer_t p_host_name
;
58 dns_name_pointer_t p_zone_name
;
59 dns_name_pointer_t p_service_name
;
60 dns_name_pointer_t p_service_instance_name
;
63 key
= srp_load_keypair(keyfile_name
);
65 key
= srp_generate_key();
67 printf("Unable to load or generate a key.");
70 if (!srp_write_key_to_file(keyfile_name
, key
)) {
71 printf("Unable to safe generated key.");
76 #define CH if (towire->error) { line = __LINE__; goto fail; }
78 // Generate a random UUID.
80 message
.id
= srp_random16();
83 message
.id
= (uint32_t)(random()) & 65535;
86 dns_qr_set(&message
, dns_qr_query
);
87 dns_opcode_set(&message
, dns_opcode_update
);
90 memset(&txn
, 0, sizeof txn
);
91 towire
->p
= &message
.data
[0]; // We start storing RR data here.
92 towire
->lim
= &message
.data
[DNS_DATA_SIZE
]; // This is the limit to how much we can store.
93 towire
->message
= &message
;
94 txn
.response
= &response
;
95 txn
.response_length
= (int)(sizeof response
);
97 message
.qdcount
= htons(1); // ZOCOUNT = 1
98 // Copy in Zone name (and save pointer)
101 dns_full_name_to_wire(&p_zone_name
, towire
, zone_name
); CH
;
102 dns_u16_to_wire(towire
, dns_rrtype_soa
); CH
;
103 dns_u16_to_wire(towire
, dns_qclass_in
); CH
;
112 // * Delete all RRsets from <hostname>; remember the pointer to hostname
113 // NAME = hostname label followed by pointer to SOA name.
118 dns_name_to_wire(&p_host_name
, towire
, host_name
); CH
;
119 dns_pointer_to_wire(&p_host_name
, towire
, &p_zone_name
); CH
;
120 dns_u16_to_wire(towire
, dns_rrtype_any
); CH
;
121 dns_u16_to_wire(towire
, dns_qclass_any
); CH
;
122 dns_ttl_to_wire(towire
, 0); CH
;
123 dns_u16_to_wire(towire
, 0); CH
;
125 // * Add either or both of an A or AAAA RRset, each of which contains one
126 // or more A or AAAA RRs.
127 // NAME = pointer to hostname from Delete (above)
131 // RDLENGTH = number of RRs * RR length (4 or 16)
132 // RDATA = <the data>
133 dns_pointer_to_wire(NULL
, towire
, &p_host_name
); CH
;
134 dns_u16_to_wire(towire
, dns_rrtype_a
); CH
;
135 dns_u16_to_wire(towire
, dns_qclass_in
); CH
;
136 dns_ttl_to_wire(towire
, 3600); CH
;
137 dns_rdlength_begin(towire
); CH
;
138 dns_rdata_a_to_wire(towire
, a_record
); CH
;
139 dns_rdlength_end(towire
); CH
;
142 dns_pointer_to_wire(NULL
, towire
, &p_host_name
); CH
;
143 dns_u16_to_wire(towire
, dns_rrtype_aaaa
); CH
;
144 dns_u16_to_wire(towire
, dns_qclass_in
); CH
;
145 dns_ttl_to_wire(towire
, 3600); CH
;
146 dns_rdlength_begin(towire
); CH
;
147 dns_rdata_aaaa_to_wire(towire
, aaaa_record
); CH
;
148 dns_rdlength_end(towire
); CH
;
151 // * Exactly one KEY RR:
152 // NAME = pointer to hostname from Delete (above)
156 // RDLENGTH = length of key + 4 (32 bits)
157 // RDATA = <flags(16) = 0000 0010 0000 0001, protocol(8) = 3, algorithm(8) = 8?, public key(variable)>
158 dns_pointer_to_wire(NULL
, towire
, &p_host_name
); CH
;
159 dns_u16_to_wire(towire
, dns_rrtype_key
); CH
;
160 dns_u16_to_wire(towire
, dns_qclass_in
); CH
;
161 dns_ttl_to_wire(towire
, 3600); CH
;
162 dns_rdlength_begin(towire
); CH
;
163 key_tag
= dns_rdata_key_to_wire(towire
, 0, 2, 1, key
); CH
;
164 dns_rdlength_end(towire
); CH
;
167 // Service Discovery:
169 // NAME = service name (_a._b.service.arpa)
174 // RDATA = service instance name
175 dns_name_to_wire(&p_service_name
, towire
, service_type
); CH
;
176 dns_pointer_to_wire(&p_service_name
, towire
, &p_zone_name
); CH
;
177 dns_u16_to_wire(towire
, dns_rrtype_ptr
); CH
;
178 dns_u16_to_wire(towire
, dns_qclass_in
); CH
;
179 dns_ttl_to_wire(towire
, 3600); CH
;
180 dns_rdlength_begin(towire
); CH
;
181 dns_name_to_wire(&p_service_instance_name
, towire
, host_name
); CH
;
182 dns_pointer_to_wire(&p_service_instance_name
, towire
, &p_service_name
); CH
;
183 dns_rdlength_end(towire
); CH
;
186 // Service Description:
187 // * Delete all RRsets from service instance name
188 // NAME = service instance name (save pointer to service name, which is the second label)
193 dns_pointer_to_wire(NULL
, towire
, &p_service_instance_name
); CH
;
194 dns_u16_to_wire(towire
, dns_rrtype_any
); CH
;
195 dns_u16_to_wire(towire
, dns_qclass_any
); CH
;
196 dns_ttl_to_wire(towire
, 0); CH
;
197 dns_u16_to_wire(towire
, 0); CH
;
200 // * Add one SRV RRset pointing to Host Description
201 // NAME = pointer to service instance name from above
206 // RDATA = <priority(16) = 0, weight(16) = 0, port(16) = service port, target = pointer to hostname>
207 dns_pointer_to_wire(NULL
, towire
, &p_service_instance_name
); CH
;
208 dns_u16_to_wire(towire
, dns_rrtype_srv
); CH
;
209 dns_u16_to_wire(towire
, dns_qclass_in
); CH
;
210 dns_ttl_to_wire(towire
, 3600); CH
;
211 dns_rdlength_begin(towire
); CH
;
212 dns_u16_to_wire(towire
, 0); // priority CH;
213 dns_u16_to_wire(towire
, 0); // weight CH;
214 dns_u16_to_wire(towire
, port
); // port CH;
215 dns_pointer_to_wire(NULL
, towire
, &p_host_name
); CH
;
216 dns_rdlength_end(towire
); CH
;
219 // * Add one or more TXT records
220 // NAME = pointer to service instance name from above
224 // RDLENGTH = <length of text>
226 dns_pointer_to_wire(NULL
, towire
, &p_service_instance_name
); CH
;
227 dns_u16_to_wire(towire
, dns_rrtype_txt
); CH
;
228 dns_u16_to_wire(towire
, dns_qclass_in
); CH
;
229 dns_ttl_to_wire(towire
, 3600); CH
;
230 dns_rdlength_begin(towire
); CH
;
231 dns_rdata_txt_to_wire(towire
, txt_record
); CH
;
232 dns_rdlength_end(towire
); CH
;
234 message
.nscount
= htons(message
.nscount
);
236 // What about services with more than one name? Are these multiple service descriptions?
243 message
.arcount
= htons(1);
244 dns_edns0_header_to_wire(towire
, DNS_MAX_UDP_PAYLOAD
, 0, 0, 1); CH
; // XRCODE = 0; VERSION = 0; DO=1
245 dns_rdlength_begin(towire
); CH
;
246 dns_u16_to_wire(towire
, dns_opt_update_lease
); CH
; // OPTION-CODE
247 dns_edns0_option_begin(towire
); CH
; // OPTION-LENGTH
248 dns_u32_to_wire(towire
, 3600); CH
; // LEASE (1 hour)
249 dns_u32_to_wire(towire
, 604800); CH
; // KEY-LEASE (7 days)
250 dns_edns0_option_end(towire
); CH
; // Now we know OPTION-LENGTH
251 dns_rdlength_end(towire
); CH
;
253 dns_sig0_signature_to_wire(towire
, key
, key_tag
, &p_host_name
, host_fqdn
); CH
;
254 // The signature is computed before counting the signature RR in the header counts.
255 message
.arcount
= htons(ntohs(message
.arcount
) + 1);
258 if (dns_send_to_server(&txn
, anycast_address
, 53, dns_response_callback
) < 0) {
261 printf("dns_send_to_server failed: %s at line %d\n", strerror(towire
->error
), line
);
268 // c-file-style: "bsd"
271 // indent-tabs-mode: nil