forked from octocat/linguist
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathxipd.coffee
More file actions
110 lines (87 loc) · 2.83 KB
/
xipd.coffee
File metadata and controls
110 lines (87 loc) · 2.83 KB
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
dnsserver = require "dnsserver"
exports.Server = class Server extends dnsserver.Server
NS_T_A = 1
NS_T_NS = 2
NS_T_CNAME = 5
NS_T_SOA = 6
NS_C_IN = 1
NS_RCODE_NXDOMAIN = 3
constructor: (domain, @rootAddress) ->
super
@domain = domain.toLowerCase()
@soa = createSOA @domain
@on "request", @handleRequest
handleRequest: (req, res) =>
question = req.question
subdomain = @extractSubdomain question.name
if subdomain? and isARequest question
res.addRR question.name, NS_T_A, NS_C_IN, 600, subdomain.getAddress()
else if subdomain?.isEmpty() and isNSRequest question
res.addRR question.name, NS_T_SOA, NS_C_IN, 600, @soa, true
else
res.header.rcode = NS_RCODE_NXDOMAIN
res.send()
extractSubdomain: (name) ->
Subdomain.extract name, @domain, @rootAddress
isARequest = (question) ->
question.type is NS_T_A and question.class is NS_C_IN
isNSRequest = (question) ->
question.type is NS_T_NS and question.class is NS_C_IN
createSOA = (domain) ->
mname = "ns-1.#{domain}"
rname = "hostmaster.#{domain}"
serial = parseInt new Date().getTime() / 1000
refresh = 28800
retry = 7200
expire = 604800
minimum = 3600
dnsserver.createSOA mname, rname, serial, refresh, retry, expire, minimum
exports.createServer = (domain, address = "127.0.0.1") ->
new Server domain, address
exports.Subdomain = class Subdomain
@extract: (name, domain, address) ->
return unless name
name = name.toLowerCase()
offset = name.length - domain.length
if domain is name.slice offset
subdomain = if 0 >= offset then null else name.slice 0, offset - 1
new constructor subdomain, address if constructor = @for subdomain
@for: (subdomain = "") ->
if IPAddressSubdomain.pattern.test subdomain
IPAddressSubdomain
else if EncodedSubdomain.pattern.test subdomain
EncodedSubdomain
else
Subdomain
constructor: (@subdomain, @address) ->
@labels = subdomain?.split(".") ? []
@length = @labels.length
isEmpty: ->
@length is 0
getAddress: ->
@address
class IPAddressSubdomain extends Subdomain
@pattern = /// (^|\.)
((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}
(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)
$ ///
getAddress: ->
@labels.slice(-4).join "."
class EncodedSubdomain extends Subdomain
@pattern = /(^|\.)[a-z0-9]{1,7}$/
getAddress: ->
decode @labels[@length - 1]
exports.encode = encode = (ip) ->
value = 0
for byte, index in ip.split "."
value += parseInt(byte, 10) << (index * 8)
(value >>> 0).toString 36
PATTERN = /^[a-z0-9]{1,7}$/
exports.decode = decode = (string) ->
return unless PATTERN.test string
value = parseInt string, 36
ip = []
for i in [1..4]
ip.push value & 0xFF
value >>= 8
ip.join "."