Mercurial > hg > marc_php
annotate marcus.php @ 1:caa68b502313 draft
Added the MARC DNS server (and small fixes in marcus and anoclaims)
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Thu, 13 Nov 2014 17:22:12 +0100 |
parents | 3ac7bd7495fd |
children | 5c8c4fa95803 |
rev | line source |
---|---|
0 | 1 <?php |
2 require_once './marccore.php'; | |
3 | |
4 error_reporting(E_ALL); | |
5 | |
6 if (!isset($argv)) $argv = $_SERVER['argv']; | |
7 $argi = 1; | |
8 | |
9 class FilteredResourceIterator implements Iterator { | |
10 private $source, $filtertype, $filtervalue; | |
11 public function __construct($source, $filtertype, $filtervalue) { | |
12 $this->source = $source; | |
13 $this->filtertype = $filtertype; | |
14 $this->filtervalue = $filtervalue; | |
15 } | |
16 public function current() { $r = $this->source->current(); return $r; } | |
17 public function key() { return $this->source->key(); } | |
18 public function valid() { return $this->source->valid(); } | |
19 public function next() { $this->source->next(); $this->findnext(); } | |
20 public function rewind() { $this->source->rewind(); $this->findnext(); } | |
21 private function findnext() { | |
22 while ($this->source->valid()) { | |
23 $c = $this->source->current(); | |
24 if ($this->filter($c)) break; | |
25 $this->source->next(); | |
26 } | |
27 } | |
28 private function filter($c) { | |
29 switch ($this->filtertype) { | |
30 case 'OWNER': return isset($c['value']['owner']) && is_scalar($c['value']['owner']) && strcasecmp($c['value']['owner'], $this->filtervalue) == 0; | |
31 case 'KEY': return $c['key'] == hex2bin($this->filtervalue); | |
32 case 'DOMEXT': return ord($c['label'][0]) == 4 && substr_compare($c['label'], $this->filtervalue, -strlen($this->filtervalue), strlen($this->filtervalue), TRUE) == 0; | |
33 default: return FALSE; | |
34 } | |
35 } | |
36 } | |
37 | |
38 $database = new MARCDatabaseFlatFile(); | |
39 $key = NULL; | |
40 $resource = NULL; | |
41 $reschanged = FALSE; | |
42 | |
43 while ($argi < count($argv)) { | |
44 switch (strtoupper($argv[$argi++])) { | |
45 case 'OPEN': | |
46 if ($reschanged) echo "Warning: selected resource has not been updated.\n"; | |
47 if ($database->IsChanged()) echo "Warning: database has unsaved changes.\n"; | |
48 $database->Open($argv[$argi++]); | |
49 $reschanged = FALSE; | |
50 break; | |
51 case 'OPENSQLITE': | |
52 $database = new MARCDatabaseSQLite($argv[$argi++]); | |
53 break; | |
54 case 'OPENDBA': | |
55 $database = new MARCDatabaseDBA($argv[$argi++]); | |
56 break; | |
57 case 'SAVE': | |
58 $database->Save(); | |
59 break; | |
60 case 'SAVEAS': | |
61 $database->SaveAs($argv[$argi]); | |
62 break; | |
63 case 'SYNC': | |
64 $database->SyncHTTP($argv[$argi++]); | |
65 break; | |
66 case 'KEY': | |
67 switch (strtoupper($argv[$argi++])) { | |
68 case 'CREATE': | |
69 $key = array('store' => TRUE); | |
70 $key['pk'] = nacl_crypto_sign_ed25519_keypair($key['sk'], randombytes(32)); | |
71 $dbchanged = TRUE; | |
72 echo 'Created public key '.bin2hex($key['pk'])."\n"; | |
73 break; | |
74 case 'FORGET': | |
75 $key['store'] = FALSE; | |
76 $dbchanged = TRUE; | |
77 break; | |
78 case 'STORE': | |
79 $key['store'] = TRUE; | |
80 $dbchanged = TRUE; | |
81 break; | |
82 case 'USE': | |
83 $key = array('store' => FALSE, 'pk' => $resource['key']); | |
84 if (isset($resource['value']['seckey'])) $key['sk'] = $resource['value']['seckey']; | |
85 if (isset($resource['value']['seckeyenc'])) $key['locked'] = $resource['value']['seckeyenc']; | |
86 break; | |
87 case 'IMPORT': | |
88 $key = array('store' => FALSE); | |
89 $key['pk'] = nacl_crypto_sign_ed25519_keypair($key['sk'], hex2bin($argv[$argi++])); | |
90 $dbchanged = TRUE; | |
91 break; | |
92 case 'UNLOCK': | |
93 if (!isset($key['locked'])) throw new Exception('The key is not locked'); | |
94 $ret = hash('sha512', $key['pk'].$argv[$argi++], TRUE); | |
95 $key['sk'] = ''; | |
96 for ($i = 0; $i < 32; $i++) $key['sk'] .= chr(ord($key['locked'][$i]) ^ ord($ret[$i])); | |
97 $ret = nacl_crypto_sign_ed25519_keypair($key['sk'], $key['sk']); | |
98 if ($ret != $key['pk']) throw new Exception('Key password is not valid'); | |
99 echo 'Unlocked public key '.bin2hex($key['pk'])."\n"; | |
100 break; | |
101 default: | |
102 throw new Exception('Unknown key operation '.$argv[$argi-1]); | |
103 } | |
104 break; | |
105 case 'LIST': | |
106 foreach ($database->GetResources() as $ret) echo labeltoname($ret['label'])."\n"; | |
107 break; | |
108 case 'FIND': | |
109 foreach (filterresources($database->GetResources(), $argv, $argi) as $ret) echo labeltoname($ret['label'])."\n"; | |
110 break; | |
111 case 'DELETE': | |
112 $database->DeleteResource($resource['label']); | |
113 break; | |
114 case 'DUMP': | |
115 dumpresource($resource); | |
116 break; | |
117 case 'UPDATE': | |
118 if (!isset($resource['key'])) $resource['key'] = $key['pk']; | |
119 unset($resource['serial']); | |
120 $res = $database->UpdateResource($resource, $key['sk']); | |
121 if (!$res) throw new Exception('Could not update resource'); | |
122 $resource = $res->ToArray(); | |
123 $reschanged = FALSE; | |
124 break; | |
125 case 'SET': | |
126 switch (strtoupper($argv[$argi++])) { | |
127 case 'OWNER': | |
128 if (!isset($resource['value']) || !is_array($resource['value'])) $resource['value'] = array(); | |
129 $resource['value']['owner'] = $argv[$argi++]; | |
130 $reschanged = TRUE; | |
131 break; | |
132 case 'DESC': | |
133 case 'DESCR': | |
134 case 'DESCRIPTION': | |
135 if (!isset($resource['value']) || !is_array($resource['value'])) $resource['value'] = array(); | |
136 $resource['value']['descr'] = $argv[$argi++]; | |
137 $reschanged = TRUE; | |
138 break; | |
139 case 'PWAUTH': | |
140 if (!isset($key['sk'])) throw new Exception('The key is not available'); | |
141 $ret = hash('sha512', $key['pk'].$argv[$argi++], TRUE); | |
142 $key['locked'] = ''; | |
143 for ($i = 0; $i < 32; $i++) $key['locked'] .= chr(ord($key['sk'][$i]) ^ ord($ret[$i])); | |
144 if (!isset($resource['value']) || !is_array($resource['value'])) $resource['value'] = array(); | |
145 $resource['value']['seckeyenc'] = $key['locked']; | |
146 $reschanged = TRUE; | |
147 break; | |
148 case 'TRANSFER': | |
149 $ret = $argv[$argi++]; | |
150 $resource['value']['transfer'] = (strtolower($ret) == 'any') ? '' : hex2bin($ret); | |
151 $reschanged = TRUE; | |
152 break; | |
153 default: | |
154 throw new Exception('Unknown set operation '.$argv[$argi-1]); | |
155 } | |
156 break; | |
157 case 'ADD': | |
158 switch (strtoupper($argv[$argi++])) { | |
159 case 'NS': | |
160 if (!isset($resource['value']) || !is_array($resource['value'])) $resource['value'] = array(); | |
161 if (!isset($resource['value']['ns']) || !is_array($resource['value']['ns'])) $resource['value']['ns'] = array(); | |
162 $nsname = $argv[$argi++]; | |
163 $nsglue = (strlen($nsname) && $nsname[strlen($nsname)-1] != '.') ? $argv[$argi++] : NULL; | |
164 if (!isset($resource['value']['ns'][$nsname]) || !is_array($resource['value']['ns'][$nsname])) $resource['value']['ns'][$nsname] = array(); | |
165 if ($nsglue !== NULL) $resource['value']['ns'][$nsname][] = $nsglue; | |
166 $reschanged = TRUE; | |
167 break; | |
168 default: | |
169 throw new Exception('Unknown add operation '.$argv[$argi-1]); | |
170 } | |
171 break; | |
172 case 'RESET': | |
173 switch (strtoupper($argv[$argi++])) { | |
174 case 'OWNER': | |
175 if (!is_array($resource['value'])) $resource['value'] = array(); | |
176 unset($resource['value']['owner']); | |
177 $reschanged = TRUE; | |
178 break; | |
179 case 'DESC': | |
180 case 'DESCR': | |
181 case 'DESCRIPTION': | |
182 if (!is_array($resource['value'])) $resource['value'] = array(); | |
183 unset($resource['value']['descr']); | |
184 $reschanged = TRUE; | |
185 break; | |
186 case 'PWAUTH': | |
187 if (!is_array($resource['value'])) $resource['value'] = array(); | |
188 unset($resource['value']['seckeyenc']); | |
189 $reschanged = TRUE; | |
190 break; | |
191 case 'NS': | |
192 if (!is_array($resource['value'])) $resource['value'] = array(); | |
193 unset($resource['value']['ns']); | |
194 $reschanged = TRUE; | |
195 break; | |
196 case 'VALUE': | |
197 $resource['value'] = array(); | |
198 $reschanged = TRUE; | |
199 break; | |
200 case 'TRANSFER': | |
201 unset($resource['transfer']); | |
202 $reschanged = TRUE; | |
203 break; | |
204 case 'EXPIRATION': | |
205 unset($resource['expiration']); | |
206 $reschanged = TRUE; | |
207 break; | |
208 default: | |
209 throw new Exception('Unknown reset operation '.$argv[$argi-1]); | |
210 } | |
211 break; | |
212 case 'CREATE': | |
213 if ($reschanged) echo "Warning: selected resource has not been updated.\n"; | |
214 $reschanged = TRUE; | |
215 $resource = array('label' => argtolabel($argv, $argi)); | |
216 break; | |
217 case 'SELECT': | |
218 if ($reschanged) echo "Warning: selected resource has not been updated.\n"; | |
219 $reschanged = FALSE; | |
220 $label = argtolabel($argv, $argi); | |
221 $resource = $database->GetResource($label); | |
222 if (!$resource) echo "Warning: resource ".labeltoname($label)." does not exist.\n"; | |
223 else $resource = $resource->ToArray(); | |
224 break; | |
225 case 'HELP': | |
226 print_help(); | |
227 break; | |
228 default: | |
229 throw new Exception('Unknown operation '.$argv[$argi-1]); | |
230 } | |
231 } | |
232 if ($reschanged) echo "Warning: selected resource has not been updated.\n"; | |
233 if ($database->IsChanged()) echo "Warning: database has unsaved changes.\n"; | |
234 $database->Close(); | |
235 | |
236 function filterresources($iterator, $argv, &$argi) { | |
237 $filtertype = strtoupper($argv[$argi++]); | |
238 switch ($filtertype) { | |
239 case 'OWNER': | |
240 case 'KEY': | |
241 case 'DOMEXT': | |
242 $filtervalue = $argv[$argi++]; | |
243 break; | |
244 default: | |
245 throw new Exception('Unknown filter type '.$t); | |
246 } | |
247 return new FilteredResourceIterator($iterator, $filtertype, $filtervalue); | |
248 } | |
249 function argtolabel($argv, &$argi) { | |
250 $t = $argv[$argi++]; | |
251 switch (strtoupper($t)) { | |
252 case 'LABEL': return hex2bin($argv[$argi++]); | |
253 case 'CURRENTKEY': return chr(0).$GLOBALS['key']['pk']; | |
254 case 'RESOURCEKEY': return chr(0).$GLOBALS['resource']['key']; | |
255 case 'KEY': return chr(0).hex2bin($argv[$argi++]); | |
256 case 'IP': | |
257 case 'IP4': | |
258 case 'IPV4': | |
259 case 'IP6': | |
260 case 'IPV6': return ipnettolabel($argv[$argi++]); | |
261 case 'AS': return chr(3).marc_decode_int32be($argv[$argi++]); | |
262 case 'DOM': | |
263 case 'DOMAIN': return chr(4).strtolower(trim($argv[$argi++], '.')); | |
264 default: | |
1
caa68b502313
Added the MARC DNS server (and small fixes in marcus and anoclaims)
Ivo Smits <Ivo@UCIS.nl>
parents:
0
diff
changeset
|
265 if (preg_match('/^AS[0-9]{1-9}$/', $t)) return chr(3).marc_decode_int32be(substr($t, 2)); |
caa68b502313
Added the MARC DNS server (and small fixes in marcus and anoclaims)
Ivo Smits <Ivo@UCIS.nl>
parents:
0
diff
changeset
|
266 if (preg_match('_^[0-9]{1-3}\.[0-9]{1-3}\.[0-9]{1-3}\.[0-9]{1-3}/[0-9]{1-2}$_', $t)) return ipnettolabel($t); |
caa68b502313
Added the MARC DNS server (and small fixes in marcus and anoclaims)
Ivo Smits <Ivo@UCIS.nl>
parents:
0
diff
changeset
|
267 if (preg_match('_^(((?=.*(::))(?!.*\3.+\3))\3?|([\dA-F]{1,4}(\3|:\b|$)|\2))(?4){5}((?4){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})\z/[0-9]{1-3}_i', $t)) return ipnettolabel($t); |
0 | 268 if (preg_match('/^[a-f0-9]{64}$/i', $t)) return chr(0).hex2bin($t); |
269 if (preg_match('/^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6}$/i', $t)) return chr(4).strtolower(trim($t, '.')); | |
270 throw new Exception('Could not detect label type for '.$t); | |
271 } | |
272 } | |
273 function ipnettolabel($s) { | |
274 $ip = inet_pton(strtok($s, '/')); | |
275 $pl = intval(strtok('/')); | |
276 if ($pl == 0) throw new Exception('Invalid IP network specified'); | |
277 if (strlen($ip) == 4) return chr(1).$ip.chr($pl); | |
278 if (strlen($ip) == 16) return chr(2).$ip.chr($pl); | |
279 } | |
280 function labeltoname($l) { | |
281 switch (ord($l)) { | |
282 case 0: return 'KEY '.bin2hex(substr($l, 1)); | |
283 case 1: if (strlen($l) == 6) return 'IPv4 '.inet_ntop(substr($l, 1, 4)).'/'.ord($l[5]); else return 'LABEL '.bin2hex($l); | |
284 case 2: if (strlen($l) == 18) return 'IPv6 '.inet_ntop(substr($l, 1, 16)).'/'.ord($l[17]); else return 'LABEL '.bin2hex($l); | |
285 case 3: if (strlen($l) == 5) return 'AS '.marc_decode_int32be(substr($l, 1, 4)); else return 'LABEL '.bin2hex($l); | |
286 case 4: if (strlen($l) > 1) return 'DOM '.substr($l, 1); else return 'LABEL '.bin2hex($l); | |
287 default: return 'LABEL '.bin2hex($l); | |
288 } | |
289 } | |
290 function dumpresource($r, $p = '') { | |
291 if (is_null($r)) { | |
292 echo "NULL\n"; | |
293 } else if (is_string($r)) { | |
294 $bin = FALSE; | |
295 for ($i = 0; $i < strlen($r); $i++) $bin |= ord($r[$i]) < 32 || ord($r[$i]) > 126; | |
296 if ($bin) echo '0x'.bin2hex($r)."\n"; | |
297 else echo '"'.$r.'"'."\n"; | |
298 } else if (is_scalar($r)) { | |
299 echo $r."\n"; | |
300 } else if (is_array($r)) { | |
301 echo "array(\n"; | |
302 foreach ($r as $key => $value) { | |
303 echo $p.' ['.$key.'] => '; | |
304 dumpresource($value, $p.' '); | |
305 } | |
306 echo $p." )\n"; | |
307 } else { | |
308 print_r($r); | |
309 } | |
310 } | |
311 function randombytes($n) { | |
312 $b = ''; | |
313 $file = fopen('/dev/urandom', 'r'); | |
314 for ($i = 0; $i < $n; $i++) $b .= fgetc($file); | |
315 fclose($file); | |
316 return $b; | |
317 } | |
318 | |
319 function print_help() { | |
320 echo 'Usage: marcus.php [operation] [arguments] [operation] [arguments]... | |
321 open [filename.mdb] - opens the specified database file | |
322 save - saves the current database file | |
323 saveas [filename.mdb] - saves the current data to a new databse file | |
324 sync [url] - synchronize database with remote server | |
325 key create - create a new key pair | |
326 key forget - do not store the current key pair in the local database | |
327 key store - store the current key pair in the local database | |
328 key use - use the key pair from the currently selected resource | |
329 key import [secretkey] - import the key pair defined by the given secret key | |
330 key unlock [password] - unlock a password protected key pair | |
331 list - list registered resources | |
332 find [type] [value] - list registered sources matching filter (type=OWNER|KEY|DOMEXT) | |
333 create [identifier] - create given resource | |
334 create currentkey - create resource for current key pair | |
335 create ip|ip4|ipv4 [ipv4network] - create resource for IPv4 network | |
336 create ip|ip6|ipv6 [ipv6network] - create resource for IPv6 network | |
337 create dom|domain [ipv6network] - create resource for domain name | |
338 select [identifier] - select resource given by identifier | |
339 select currentkey - select key resource for current key pair | |
340 select resourcekey - select key resource for the key that signed the currently selected resource | |
341 select label [identifier] - select resource by hexadecimal label | |
342 select key [publickey] - select key resource (hexadecimal) | |
343 select ip|ip4|ipv4 [ipv4network] - select resource for IPv4 network | |
344 select ip|ip6|ipv6 [ipv6network] - select resource for IPv6 network | |
345 select dom|domain [ipv6network] - select resource for domain name | |
346 delete - delete currently selected resource | |
347 dump - display currently selected resource | |
348 update - update selected resource in the local database | |
349 set owner [name] - set the owner name for the selected resource | |
350 set descr|desc|description [text] - set the description for the selected resource | |
351 set pwauth [password] - store the current key pair in the selected resource for password authentication | |
352 set transfer any - allow anyone to take over the resource | |
353 set transfer [key] - transfer the resource to given key | |
354 TODO: set expiration [value] | |
355 add ns [name] [glue] - add in-zone nameserver with glue record (name is the part of the nameserver name before the domain name, glue is an IPv4 or IPv6 address) | |
356 add ns [name]. - add an external nameserver | |
357 reset owner - clear the owner | |
358 reset descr|desc|description - clear the description | |
359 reset pwauth - remove the key pair from the recourse, disabling password authentication | |
360 reset ns - clear the nameserver records | |
361 reset transfer - disable resource transfers | |
362 reset expiration - disable explicit expiration | |
363 reset value - clear the owner, description, password authentication and nameserver records | |
364 | |
365 Examples: | |
366 OPEN marc.mdb KEY create CREATE currentkey SET owner "Your name" SET pwauth yourpassword UPDATE KEY forget CREATE yourdomain.ano SET owner "Your name" UPDATE SAVE | |
367 OPEN marc.mdb SELECT yourdomain.ano SELECT resourcekey KEY use KEY unlock yourpassword SELECT yourdomain.ano ADD ns ns1 1.2.3.4 UPDATE SAVE | |
368 OPEN marc.mdb SELECT yourdomain.ano SELECT resourcekey KEY use KEY unlock yourpassword CREATE 1.2.3.0/24 SET owner "Your name" ADD ns ns1.yourdomain.ano. UPDATE SAVE | |
369 OPEN marc.mdb SYNC http://marc.ucis.ano/ SAVE | |
370 '; | |
371 } |