git ssb

15+

ansuz / dnssb



Tree: 7f0916643cf58906cafbf0ff7d3700b5bb09328f

Files: 7f0916643cf58906cafbf0ff7d3700b5bb09328f / lib / query.js

4642 bytesRaw
1var Pull = require("pull-stream");
2var KVSet = require("kvset");
3var Pad = require("pad-ipv6");
4var Query = module.exports = {};
5
6Query.branches = function (sbot, name, type, _class, cb) {
7 if (!_class) _class = "IN";
8 var branches = [];
9 Pull(Query.all(sbot),
10 Pull.filter(function (record) {
11 return record.name == name
12 && record.type == type
13 && record.class == _class;
14 }),
15 Query.drainSet(function (record) {
16 branches.push(record.id);
17 }, function (err) {
18 cb(err, branches);
19 }));
20};
21
22function msgToRecord(msg) {
23 var c = msg.value.content;
24 var r = c && c.record;
25 if (!r) return;
26 r.id = msg.key;
27 r.author = msg.value.author;
28 r.timestamp = msg.value.timestamp;
29 r.branch = c.branch;
30 if (!r.ttl) r.ttl = 500;
31 if (!r.class) r.class = "IN";
32 if (r.value) r.data = r.value, delete r.value
33 if (r.type === 'AAAA') r.data = Pad(r.data);
34 return r;
35}
36
37Query.all = function (sbot) {
38 return Pull(sbot.messagesByType({
39 type: 'ssb-dns',
40 }),
41 Pull.map(msgToRecord),
42 Pull.filter());
43};
44
45function expandName(name, wildcard) {
46 var names = {};
47 for (var labels = name.split(/\./); labels.length; labels.shift()) {
48 if (wildcard) labels[0] = wildcard;
49 names[labels.join('.')] = true;
50 }
51 return names;
52}
53
54function Wildcards() {
55 this.lengths = [];
56 this.recordsByLength = {};
57}
58
59Wildcards.prototype.addRecord = function (record) {
60 var len = record.name.length;
61 if (len in this.recordsByLength) {
62 this.recordsByLength[len].push(record);
63 } else {
64 this.recordsByLength[len] = [record];
65 this.lengths.push(len);
66 }
67};
68
69Wildcards.prototype.getRecords = function () {
70 // get records for the longest name length
71 if (this.lengths.length) {
72 var len = Math.max.apply(Math, this.lengths);
73 return this.recordsByLength[len] || [];
74 }
75 return [];
76};
77
78function ZoneSerials() {
79 this.serials = {};
80}
81
82ZoneSerials.prototype.addRecord = function (record) {
83 for (var zone in expandName(record.name)) {
84 this.serials[zone] = (+this.serials[zone] || 0) + 1;
85 }
86};
87
88ZoneSerials.prototype.getSerial = function (zone) {
89 return this.serials[zone] % 0x100000000;
90};
91
92Query.drainSet = function (each, onEnd) {
93 var set = new KVSet();
94 return Pull.drain(function (record) {
95 if (record.branch) set.remove(record.branch);
96 set.add(record.id, record);
97 }, function (err) {
98 if (err) return onEnd(err);
99 for (var key in set.heads) {
100 var record = set.heads[key];
101 try {
102 each(record);
103 } catch(e) {
104 return onEnd(e);
105 }
106 }
107 onEnd(null);
108 });
109};
110
111Query.query = function (sbot, question, cb) {
112 // look up records that match a question, including wildcard records
113 // and zone authority records
114 var authorityDomains = expandName(question.name);
115 var wildcardDomains = expandName(question.name, '*');
116 var authorities = new Wildcards();
117 var answers = new Wildcards();
118 var zoneSerials = new ZoneSerials();
119 var result = {};
120 Pull(Query.all(sbot),
121 Pull.filter(function (record) {
122 zoneSerials.addRecord(record);
123 var nameMatches = record.name == question.name
124 || record.name in wildcardDomains
125 if (nameMatches) {
126 result.domainExists = true;
127 }
128 if (record.type === 'SOA') {
129 return record.name in authorityDomains
130 }
131 return nameMatches
132 && record.type == question.type
133 && record.class == question.class;
134 }),
135 Query.drainSet(function (record) {
136 if (record.type === 'SOA') {
137 result.authoritative = true;
138 if (question.type === 'SOA'
139 && question.class === record.class
140 && (question.name === record.name
141 || record.name in wildcardDomains)) {
142 answers.addRecord(record);
143 } else {
144 authorities.addRecord(record);
145 }
146 } else {
147 answers.addRecord(record);
148 }
149 }, function (err) {
150 if (err) return cb(err);
151 result.answers = answers.getRecords();
152 result.authorities = authorities.getRecords();
153 result.authorities.forEach(function (auth) {
154 if (!auth.data.serial) {
155 // special case: calculate a serial for the SOA
156 auth.data.serial = zoneSerials.getSerial(auth.name);
157 }
158 });
159 cb(null, result);
160 }));
161};
162

Built with git-ssb-web