File: NOTES.dns-srv

package info (click to toggle)
proftpd-mod-proxy 0.9.2-1%2Bdeb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 4,972 kB
  • sloc: perl: 43,469; ansic: 43,171; sh: 3,479; makefile: 247
file content (397 lines) | stat: -rw-r--r-- 11,731 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397

Use Docker Compose and:

  proftpd+mod_proxy
  proftpd/pure-ftpd
  dnsmasq

Implementation:

  ProxyDNSOptions
    UseSRV (or +SRV)
    UseTXT (or +TXT)

  * allows room for later -A, -AAA

  OR, even better:

    ftp+srv://server.example.com
    ftps+srv://server.example.com

  DNS SRV query:

    _ftp._tcp.server.example.com

  Same for TXT records?

    ftp+txt://server.example.com
    ftps+txt://server.example.com

  See:
    https://docs.mongodb.com/manual/reference/connection-string/#connections-dns-seedlist

  These would require changes to the URI parsing, Conn API, for "hints"?

  NOTE: Port numbers are NOT allowed in the URL if the SRV scheme is used!
    Why not?  Because port numbers are returned in the SRV records themselves;
    avoid any possible collisions/conflicts.  Besides, mutiple SRV records
    for the same service name might have different ports.

    Similarly for TXT scheme; the port will be part of the URLs found in
    the TXT records.

    If ports ARE found in such URLs, they will be (logged and) ignored.

  NOTE:
    TXT records found to have URLs must NOT use the +txt, +srv schemes.

  lib/proxy/dns.c

    typedef enum {
      PROXY_DNS_SRV,
      PROXY_DNS_TXT
    } proxy_dns_typ_e;

    int proxy_dns_resolve(pool *p, const char *name, proxy_dns_type_e dns_type,
      array_header **addrs);

  NOTE:
    Check that the A, AAAA records for SRV targets MATCH the initial name's
    domain.  If there is a domain mismatch, do we reject/skip that target?
      Answer: For now, no.  Accept the given target names.

  NOTE: Watch/honor the TTLs on the retrieved records.  A given SRV record
    will have its own TTL; the target resource records (included, or
    retrieved separately) will have their own TTLs (often shorter).  Even
    if we go with the shortest TTL, and set a timer, that timer will be
    specific to that pconn object.

  In order to honor the TTLs, we'd need to schedule timers -- but only in
  the daemon/master process, NOT session/child processes.  (Thus we'd need
  to remove these re-resolve timers on sess_init.)  We would need to
  track the timer ID in the pconn struct; the timer callback would take
  that pconn as an argument, to update the addr, port, other addrs.  And
  what about the memory pool to use for re-resolves, considering a long-lived
  daemon process?

    If resolution fails in timer, leave existing pconn (and timer) as is.

  These TTL timers ONLY need to be there for URLs parsed at start-up time,
  by the daemon/master process.  This means we don't need it for URLs
  obtained from SQL databases, Redis servers, per-user/group, etc.


Test:

  SRV records:
    one
    none
      per RFC 2782, if none, fallback to A record.
    multiple
    multiple weighted/prioritized

    * when to query/look at RRs in "additional data" section?  ns_s_ar (vs ns_s_an)?

Answer:

   Target
        The domain name of the target host.  There MUST be one or more
        address records for this name, the name MUST NOT be an alias (in
        the sense of RFC 1034 or RFC 2181).  Implementors are urged, but
        not required, to return the address record(s) in the Additional
        Data section.  Unless and until permitted by future standards
        action, name compression is not to be used for this field.

        A Target of "." means that the service is decidedly not
        available at this domain.

Need an example for testing?

$ dig _imaps._tcp.gmail.com SRV

  ; <<>> DiG 9.8.3-P1 <<>> _imaps._tcp.gmail.com SRV
  ;; global options: +cmd
  ;; Got answer:
  ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 17898
  ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 4

  ;; QUESTION SECTION:
  ;_imaps._tcp.gmail.com.		IN	SRV

  ;; ANSWER SECTION:
  _imaps._tcp.gmail.com.	86400	IN	SRV	5 0 993 imap.gmail.com.

  ;; ADDITIONAL SECTION:
  imap.gmail.com.		96	IN	A	74.125.20.108
  imap.gmail.com.		96	IN	A	74.125.20.109
  imap.gmail.com.		96	IN	AAAA	2607:f8b0:400e:c08::6d
  imap.gmail.com.		96	IN	AAAA	2607:f8b0:400e:c08::6c

Note that `dig gmail.com ANY` does NOT return the SRV records; you have to
query for them specifically.  This also means that the name to be resolved
must be specifically constructed for SRV lookup!

  ftp+srv://example.com  -> _ftp._tcp.example.com
  ftps+srv://example.com -> _ftp._tcp.example.com

Fun -- watch what happens for different nameservers:

# Here, we get the add'l records...
$ dig _imaps._tcp.gmail.com SRV @75.75.75.75

; <<>> DiG 9.8.3-P1 <<>> _imaps._tcp.gmail.com SRV @75.75.75.75
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 9937
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 4

;; QUESTION SECTION:
;_imaps._tcp.gmail.com.		IN	SRV

;; ANSWER SECTION:
_imaps._tcp.gmail.com.	86400	IN	SRV	5 0 993 imap.gmail.com.

;; ADDITIONAL SECTION:
imap.gmail.com.		79	IN	A	74.125.195.108
imap.gmail.com.		79	IN	A	74.125.195.109
imap.gmail.com.		79	IN	AAAA	2607:f8b0:400e:c04::6d
imap.gmail.com.		79	IN	AAAA	2607:f8b0:400e:c04::6c

;; Query time: 32 msec
;; SERVER: 75.75.75.75#53(75.75.75.75)
;; WHEN: Sat Nov 14 20:13:05 2020
;; MSG SIZE  rcvd: 161

# Here, we do NOT get the add'l records.  Something to handle.
$ dig _imaps._tcp.gmail.com SRV @8.8.8.8

; <<>> DiG 9.8.3-P1 <<>> _imaps._tcp.gmail.com SRV @8.8.8.8
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24242
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;_imaps._tcp.gmail.com.		IN	SRV

;; ANSWER SECTION:
_imaps._tcp.gmail.com.	21599	IN	SRV	5 0 993 imap.gmail.com.

;; Query time: 30 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Sat Nov 14 20:13:59 2020
;; MSG SIZE  rcvd: 73

Means that some resolvers might helpfully fill in the add'l records.

Need to find (or configure) multiple SRV records, pointing at different targets;
what would the add'l section look like for that?

Here's an example where the target does NOT match the domain:

$ dig _sipfederationtls._tcp.outlook.com SRV

; <<>> DiG 9.8.3-P1 <<>> _sipfederationtls._tcp.outlook.com SRV
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7910
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;_sipfederationtls._tcp.outlook.com. IN	SRV

;; ANSWER SECTION:
_sipfederationtls._tcp.outlook.com. 300	IN SRV	10 2 5061 federation.messenger.msn.com.

;; Query time: 38 msec
;; SERVER: 75.75.75.75#53(75.75.75.75)
;; WHEN: Sat Nov 14 20:20:46 2020
;; MSG SIZE  rcvd: 100

Another fun one -- note the LACK of add'l data this time!
 * found here: https://stackoverflow.com/questions/10138844/java-dns-lookup-for-srv-records

$ dig _nicname._tcp.uk SRV

; <<>> DiG 9.8.3-P1 <<>> _nicname._tcp.uk SRV
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49671
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;_nicname._tcp.uk.		IN	SRV

;; ANSWER SECTION:
_nicname._tcp.uk.	172800	IN	SRV	0 0 43 whois.nic.uk.

;; Query time: 42 msec
;; SERVER: 75.75.75.75#53(75.75.75.75)
;; WHEN: Sat Nov 14 20:41:50 2020
;; MSG SIZE  rcvd: 66

And here:

$ dig _ldap._tcp.ru.ac.za SRV

; <<>> DiG 9.8.3-P1 <<>> _ldap._tcp.ru.ac.za SRV
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56234
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;_ldap._tcp.ru.ac.za.		IN	SRV

;; ANSWER SECTION:
_ldap._tcp.ru.ac.za.	21600	IN	SRV	1 0 389 bushbaby.ru.ac.za.
_ldap._tcp.ru.ac.za.	21600	IN	SRV	2 0 389 jackal.ru.ac.za.
_ldap._tcp.ru.ac.za.	21600	IN	SRV	2 0 389 gecko.ru.ac.za.

;; Query time: 167 msec
;; SERVER: 75.75.75.75#53(75.75.75.75)
;; WHEN: Sun Nov 15 09:25:27 2020
;; MSG SIZE  rcvd: 143

What about sftp?  What will the published service name be for that?  ssh,
or sftp?
  https://github.com/Crosse/sshsrv

  TXT records:
    one
    none
    multiple
    non-FTP URLs

CLI:

  # For host, dig commands
  $ apt-get install -y bind9-host dnsutils

  $ dig _ftp._tcp.castaglia.local SRV
  ...
  ;; ANSWER SECTION:
  _ftp._tcp.castaglia.local. 0	IN	SRV	3 0 2121 proxy.castaglia.org.

  $ dig castaglia.local TXT
  ...
  ;; ANSWER SECTION:
  castaglia.local.	0	IN	TXT	"foo bar baz"


References:
  https://gist.github.com/ajdavis/e5f5ddbf50b5aecdc5e1d686d72a8a7a
  https://stackoverflow.com/questions/58845991/make-the-dns-server-of-docker-container-another-docker-container-running-dnsmasq
  https://alejandrocelaya.blog/2017/04/21/set-specific-ip-addresses-to-docker-containers-created-with-docker-compose/
  https://oliver-kaestner.de/english-c-query-srv-dns-record-with-example/
  https://tools.ietf.org/html/rfc2782 (DNS SRV)
  https://people.samba.org/bzr/jerry/slag/unix/query-srv.c
  https://docs.mongodb.com/manual/reference/connection-string/

  https://jdebp.eu/FGA/dns-srv-record-use-by-clients.html
    http://dns.vanrein.org/srv/tools/

  https://github.com/lavv17/lftp/blob/master/src/Resolver.cc
  https://github.com/systemmonkey42/libsrv/blob/master/src/libsrv.c

  https://tools.ietf.org/html/draft-andrews-http-srv-01
  https://tools.ietf.org/html/draft-jennings-http-srv-05

Future:

  For A records:
    https://github.com/haproxy/haproxy/blob/master/src/dns.c#L971

  For AAAA records:
    https://github.com/haproxy/haproxy/blob/master/src/dns.c#L1032

  For CNAME records:
    https://github.com/haproxy/haproxy/blob/master/src/dns.c#L981

Tidbits:

This is already handled automagically by res_query(3), but for reference:

static int dns_check_response(ns_msg *msgh, const char *query_type) {
  int flag, res;

  flag = ns_msg_getflag(*msgh, ns_f_rcode);
  switch (flag) {
    case ns_r_noerror:
      res = 0;
      break;

    case ns_r_formerr:
      pr_trace_msg(trace_channel, 7,
        "received 'Format error' response code (%d) in %s answer", flag,
        query_type);
      errno = EINVAL;
      res = -1;
      break;

    case ns_r_servfail:
      pr_trace_msg(trace_channel, 7,
        "received 'Server failure' response code (%d) in %s answer", flag,
        query_type);
      errno = EPERM;
      res = -1;
      break;

    case ns_r_nxdomain:
      pr_trace_msg(trace_channel, 7,
        "received 'No such domain' response code (%d) in %s answer", flag,
        query_type);
      errno = ENOENT;
      res = -1;
      break;

    case ns_r_notimpl:
      pr_trace_msg(trace_channel, 7,
        "received 'Unimplemented' response code (%d) in %s answer", flag,
        query_type);
      errno = EPERM;
      res = -1;
      break;

    case ns_r_refused:
      pr_trace_msg(trace_channel, 7,
        "received 'Operation refused' response code (%d) in %s answer", flag,
        query_type);
      errno = EPERM;
      res = -1;
      break;

    default:
      pr_trace_msg(trace_channel, 7,
        "received unknown response code (%d) in %s answer", flag, query_type);
      errno = EPERM;
      res = -1;
  }

  if (res < 0) {
    return -1;
  }

  if (pr_trace_get_level(trace_channel) <= 7) {
    return res;
  }

  /* Log any other flags of interest.
   *
   * If the response was truncated, the libc resolver's default behavior is
   * to retry the query over TCP.  Given that, the main flag of interest is
   * whether this answer was authoritative (from the authoritative nameserver)
   * or from some cache along the way.
   */
  flag = ns_msg_getflag(*msgh, ns_f_aa);
  if (flag) {
    pr_trace_msg(trace_channel, 9,
      "received AUTHORITATIVE answer for %s query", query_type);

  } else {
    pr_trace_msg(trace_channel, 19,
      "received cached answer for %s query", query_type);
  }

  return res;
}