Mercurial > hg > marc_php
annotate marcus.php @ 4:c642254dc9ee draft default tip
Fixed transfer chain generation and construction of empty updates, some small improvements in tools
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Sat, 22 Nov 2014 18:18:52 +0100 |
parents | 5c8c4fa95803 |
children |
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 echo 'Created public key '.bin2hex($key['pk'])."\n"; | |
72 break; | |
73 case 'FORGET': | |
74 $key['store'] = FALSE; | |
75 break; | |
76 case 'STORE': | |
77 $key['store'] = TRUE; | |
78 break; | |
79 case 'USE': | |
80 $key = array('store' => FALSE, 'pk' => $resource['key']); | |
3
5c8c4fa95803
Added support for transfer chaining and some bugfixes
Ivo Smits <Ivo@UCIS.nl>
parents:
1
diff
changeset
|
81 if (isset($resource['value']['seckey'])) $key['locked'] = $resource['value']['seckey']; |
0 | 82 break; |
83 case 'IMPORT': | |
84 $key = array('store' => FALSE); | |
85 $key['pk'] = nacl_crypto_sign_ed25519_keypair($key['sk'], hex2bin($argv[$argi++])); | |
86 break; | |
87 case 'UNLOCK': | |
88 if (!isset($key['locked'])) throw new Exception('The key is not locked'); | |
3
5c8c4fa95803
Added support for transfer chaining and some bugfixes
Ivo Smits <Ivo@UCIS.nl>
parents:
1
diff
changeset
|
89 if (!is_array($key['locked']) || !isset($key['locked']['key'])) throw new Exception('The locked key is invalid'); |
5c8c4fa95803
Added support for transfer chaining and some bugfixes
Ivo Smits <Ivo@UCIS.nl>
parents:
1
diff
changeset
|
90 $rounds = isset($key['locked']['rounds']) ? intval($key['locked']['rounds']) : 0; |
5c8c4fa95803
Added support for transfer chaining and some bugfixes
Ivo Smits <Ivo@UCIS.nl>
parents:
1
diff
changeset
|
91 $ret = str_repeat(chr(0), 64); |
5c8c4fa95803
Added support for transfer chaining and some bugfixes
Ivo Smits <Ivo@UCIS.nl>
parents:
1
diff
changeset
|
92 for ($i = 0; $i < $rounds; $i++) $ret = hash('sha512', $ret.$argv[$argi].$key['pk'], TRUE); |
5c8c4fa95803
Added support for transfer chaining and some bugfixes
Ivo Smits <Ivo@UCIS.nl>
parents:
1
diff
changeset
|
93 $argi++; |
5c8c4fa95803
Added support for transfer chaining and some bugfixes
Ivo Smits <Ivo@UCIS.nl>
parents:
1
diff
changeset
|
94 $ret = substr($key['locked'] ^ $ret, 0, 32); |
5c8c4fa95803
Added support for transfer chaining and some bugfixes
Ivo Smits <Ivo@UCIS.nl>
parents:
1
diff
changeset
|
95 $ret = nacl_crypto_sign_ed25519_keypair($key['sk'], $ret); |
0 | 96 if ($ret != $key['pk']) throw new Exception('Key password is not valid'); |
97 echo 'Unlocked public key '.bin2hex($key['pk'])."\n"; | |
98 break; | |
99 default: | |
100 throw new Exception('Unknown key operation '.$argv[$argi-1]); | |
101 } | |
102 break; | |
103 case 'LIST': | |
104 foreach ($database->GetResources() as $ret) echo labeltoname($ret['label'])."\n"; | |
105 break; | |
106 case 'FIND': | |
107 foreach (filterresources($database->GetResources(), $argv, $argi) as $ret) echo labeltoname($ret['label'])."\n"; | |
108 break; | |
109 case 'DELETE': | |
110 $database->DeleteResource($resource['label']); | |
111 break; | |
112 case 'DUMP': | |
113 dumpresource($resource); | |
114 break; | |
115 case 'UPDATE': | |
116 if (!isset($resource['key'])) $resource['key'] = $key['pk']; | |
117 unset($resource['serial']); | |
118 $res = $database->UpdateResource($resource, $key['sk']); | |
119 if (!$res) throw new Exception('Could not update resource'); | |
120 $resource = $res->ToArray(); | |
121 $reschanged = FALSE; | |
122 break; | |
123 case 'SET': | |
124 switch (strtoupper($argv[$argi++])) { | |
125 case 'OWNER': | |
126 if (!isset($resource['value']) || !is_array($resource['value'])) $resource['value'] = array(); | |
127 $resource['value']['owner'] = $argv[$argi++]; | |
128 $reschanged = TRUE; | |
129 break; | |
130 case 'DESC': | |
131 case 'DESCR': | |
132 case 'DESCRIPTION': | |
133 if (!isset($resource['value']) || !is_array($resource['value'])) $resource['value'] = array(); | |
134 $resource['value']['descr'] = $argv[$argi++]; | |
135 $reschanged = TRUE; | |
136 break; | |
137 case 'PWAUTH': | |
138 if (!isset($key['sk'])) throw new Exception('The key is not available'); | |
3
5c8c4fa95803
Added support for transfer chaining and some bugfixes
Ivo Smits <Ivo@UCIS.nl>
parents:
1
diff
changeset
|
139 $rounds = 5000; |
5c8c4fa95803
Added support for transfer chaining and some bugfixes
Ivo Smits <Ivo@UCIS.nl>
parents:
1
diff
changeset
|
140 $ret = str_repeat(chr(0), 64); |
5c8c4fa95803
Added support for transfer chaining and some bugfixes
Ivo Smits <Ivo@UCIS.nl>
parents:
1
diff
changeset
|
141 for ($i = 0; $i < $rounds; $i++) $ret = hash('sha512', $ret.$argv[$argi].$key['pk'], TRUE); |
5c8c4fa95803
Added support for transfer chaining and some bugfixes
Ivo Smits <Ivo@UCIS.nl>
parents:
1
diff
changeset
|
142 $argi++; |
5c8c4fa95803
Added support for transfer chaining and some bugfixes
Ivo Smits <Ivo@UCIS.nl>
parents:
1
diff
changeset
|
143 $key['locked'] = array('rounds' => $rounds, 'key' => substr($key['sk'] ^ $hash, 0, 32)); |
0 | 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; | |
4
c642254dc9ee
Fixed transfer chain generation and construction of empty updates, some small improvements in tools
Ivo Smits <Ivo@UCIS.nl>
parents:
3
diff
changeset
|
220 if (strcasecmp($argv[$argi], 'TRANSFERCHAIN') == 0) { |
c642254dc9ee
Fixed transfer chain generation and construction of empty updates, some small improvements in tools
Ivo Smits <Ivo@UCIS.nl>
parents:
3
diff
changeset
|
221 $resource = MARCUpdate::Decode($resource['transferchain']); |
c642254dc9ee
Fixed transfer chain generation and construction of empty updates, some small improvements in tools
Ivo Smits <Ivo@UCIS.nl>
parents:
3
diff
changeset
|
222 if (!$resource) echo "Warning: failed to decode chained transfer data.\n"; |
c642254dc9ee
Fixed transfer chain generation and construction of empty updates, some small improvements in tools
Ivo Smits <Ivo@UCIS.nl>
parents:
3
diff
changeset
|
223 $argi++; |
c642254dc9ee
Fixed transfer chain generation and construction of empty updates, some small improvements in tools
Ivo Smits <Ivo@UCIS.nl>
parents:
3
diff
changeset
|
224 } else { |
c642254dc9ee
Fixed transfer chain generation and construction of empty updates, some small improvements in tools
Ivo Smits <Ivo@UCIS.nl>
parents:
3
diff
changeset
|
225 $label = argtolabel($argv, $argi); |
c642254dc9ee
Fixed transfer chain generation and construction of empty updates, some small improvements in tools
Ivo Smits <Ivo@UCIS.nl>
parents:
3
diff
changeset
|
226 $resource = $database->GetResource($label); |
c642254dc9ee
Fixed transfer chain generation and construction of empty updates, some small improvements in tools
Ivo Smits <Ivo@UCIS.nl>
parents:
3
diff
changeset
|
227 if (!$resource) echo "Warning: resource ".labeltoname($label)." does not exist.\n"; |
c642254dc9ee
Fixed transfer chain generation and construction of empty updates, some small improvements in tools
Ivo Smits <Ivo@UCIS.nl>
parents:
3
diff
changeset
|
228 } |
c642254dc9ee
Fixed transfer chain generation and construction of empty updates, some small improvements in tools
Ivo Smits <Ivo@UCIS.nl>
parents:
3
diff
changeset
|
229 if ($resource) $resource = $resource->ToArray(); |
0 | 230 break; |
231 case 'HELP': | |
232 print_help(); | |
233 break; | |
234 default: | |
235 throw new Exception('Unknown operation '.$argv[$argi-1]); | |
236 } | |
237 } | |
238 if ($reschanged) echo "Warning: selected resource has not been updated.\n"; | |
239 if ($database->IsChanged()) echo "Warning: database has unsaved changes.\n"; | |
240 $database->Close(); | |
241 | |
242 function filterresources($iterator, $argv, &$argi) { | |
243 $filtertype = strtoupper($argv[$argi++]); | |
244 switch ($filtertype) { | |
245 case 'OWNER': | |
246 case 'KEY': | |
247 case 'DOMEXT': | |
248 $filtervalue = $argv[$argi++]; | |
249 break; | |
250 default: | |
251 throw new Exception('Unknown filter type '.$t); | |
252 } | |
253 return new FilteredResourceIterator($iterator, $filtertype, $filtervalue); | |
254 } | |
255 function argtolabel($argv, &$argi) { | |
256 $t = $argv[$argi++]; | |
257 switch (strtoupper($t)) { | |
258 case 'LABEL': return hex2bin($argv[$argi++]); | |
259 case 'CURRENTKEY': return chr(0).$GLOBALS['key']['pk']; | |
260 case 'RESOURCEKEY': return chr(0).$GLOBALS['resource']['key']; | |
261 case 'KEY': return chr(0).hex2bin($argv[$argi++]); | |
262 case 'IP': | |
263 case 'IP4': | |
264 case 'IPV4': | |
265 case 'IP6': | |
266 case 'IPV6': return ipnettolabel($argv[$argi++]); | |
267 case 'AS': return chr(3).marc_decode_int32be($argv[$argi++]); | |
268 case 'DOM': | |
269 case 'DOMAIN': return chr(4).strtolower(trim($argv[$argi++], '.')); | |
270 default: | |
1
caa68b502313
Added the MARC DNS server (and small fixes in marcus and anoclaims)
Ivo Smits <Ivo@UCIS.nl>
parents:
0
diff
changeset
|
271 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
|
272 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
|
273 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 | 274 if (preg_match('/^[a-f0-9]{64}$/i', $t)) return chr(0).hex2bin($t); |
4
c642254dc9ee
Fixed transfer chain generation and construction of empty updates, some small improvements in tools
Ivo Smits <Ivo@UCIS.nl>
parents:
3
diff
changeset
|
275 if (preg_match('/^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z0-9]{2,6}$/i', $t)) return chr(4).strtolower(trim($t, '.')); |
0 | 276 throw new Exception('Could not detect label type for '.$t); |
277 } | |
278 } | |
279 function ipnettolabel($s) { | |
280 $ip = inet_pton(strtok($s, '/')); | |
281 $pl = intval(strtok('/')); | |
282 if ($pl == 0) throw new Exception('Invalid IP network specified'); | |
283 if (strlen($ip) == 4) return chr(1).$ip.chr($pl); | |
284 if (strlen($ip) == 16) return chr(2).$ip.chr($pl); | |
285 } | |
286 function labeltoname($l) { | |
287 switch (ord($l)) { | |
288 case 0: return 'KEY '.bin2hex(substr($l, 1)); | |
289 case 1: if (strlen($l) == 6) return 'IPv4 '.inet_ntop(substr($l, 1, 4)).'/'.ord($l[5]); else return 'LABEL '.bin2hex($l); | |
290 case 2: if (strlen($l) == 18) return 'IPv6 '.inet_ntop(substr($l, 1, 16)).'/'.ord($l[17]); else return 'LABEL '.bin2hex($l); | |
291 case 3: if (strlen($l) == 5) return 'AS '.marc_decode_int32be(substr($l, 1, 4)); else return 'LABEL '.bin2hex($l); | |
292 case 4: if (strlen($l) > 1) return 'DOM '.substr($l, 1); else return 'LABEL '.bin2hex($l); | |
293 default: return 'LABEL '.bin2hex($l); | |
294 } | |
295 } | |
296 function dumpresource($r, $p = '') { | |
297 if (is_null($r)) { | |
298 echo "NULL\n"; | |
299 } else if (is_string($r)) { | |
300 $bin = FALSE; | |
301 for ($i = 0; $i < strlen($r); $i++) $bin |= ord($r[$i]) < 32 || ord($r[$i]) > 126; | |
302 if ($bin) echo '0x'.bin2hex($r)."\n"; | |
303 else echo '"'.$r.'"'."\n"; | |
304 } else if (is_scalar($r)) { | |
305 echo $r."\n"; | |
306 } else if (is_array($r)) { | |
307 echo "array(\n"; | |
308 foreach ($r as $key => $value) { | |
309 echo $p.' ['.$key.'] => '; | |
310 dumpresource($value, $p.' '); | |
311 } | |
312 echo $p." )\n"; | |
313 } else { | |
314 print_r($r); | |
315 } | |
316 } | |
317 function randombytes($n) { | |
318 $b = ''; | |
319 $file = fopen('/dev/urandom', 'r'); | |
320 for ($i = 0; $i < $n; $i++) $b .= fgetc($file); | |
321 fclose($file); | |
322 return $b; | |
323 } | |
324 | |
325 function print_help() { | |
326 echo 'Usage: marcus.php [operation] [arguments] [operation] [arguments]... | |
327 open [filename.mdb] - opens the specified database file | |
328 save - saves the current database file | |
329 saveas [filename.mdb] - saves the current data to a new databse file | |
330 sync [url] - synchronize database with remote server | |
331 key create - create a new key pair | |
332 key forget - do not store the current key pair in the local database | |
333 key store - store the current key pair in the local database | |
334 key use - use the key pair from the currently selected resource | |
335 key import [secretkey] - import the key pair defined by the given secret key | |
336 key unlock [password] - unlock a password protected key pair | |
337 list - list registered resources | |
338 find [type] [value] - list registered sources matching filter (type=OWNER|KEY|DOMEXT) | |
339 create [identifier] - create given resource | |
340 create currentkey - create resource for current key pair | |
341 create ip|ip4|ipv4 [ipv4network] - create resource for IPv4 network | |
342 create ip|ip6|ipv6 [ipv6network] - create resource for IPv6 network | |
343 create dom|domain [ipv6network] - create resource for domain name | |
344 select [identifier] - select resource given by identifier | |
345 select currentkey - select key resource for current key pair | |
346 select resourcekey - select key resource for the key that signed the currently selected resource | |
4
c642254dc9ee
Fixed transfer chain generation and construction of empty updates, some small improvements in tools
Ivo Smits <Ivo@UCIS.nl>
parents:
3
diff
changeset
|
347 select transferchain - extract the chained transfer data from the currently selected resource |
0 | 348 select label [identifier] - select resource by hexadecimal label |
349 select key [publickey] - select key resource (hexadecimal) | |
350 select ip|ip4|ipv4 [ipv4network] - select resource for IPv4 network | |
351 select ip|ip6|ipv6 [ipv6network] - select resource for IPv6 network | |
352 select dom|domain [ipv6network] - select resource for domain name | |
353 delete - delete currently selected resource | |
354 dump - display currently selected resource | |
355 update - update selected resource in the local database | |
356 set owner [name] - set the owner name for the selected resource | |
357 set descr|desc|description [text] - set the description for the selected resource | |
358 set pwauth [password] - store the current key pair in the selected resource for password authentication | |
359 set transfer any - allow anyone to take over the resource | |
360 set transfer [key] - transfer the resource to given key | |
361 TODO: set expiration [value] | |
362 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) | |
363 add ns [name]. - add an external nameserver | |
364 reset owner - clear the owner | |
365 reset descr|desc|description - clear the description | |
366 reset pwauth - remove the key pair from the recourse, disabling password authentication | |
367 reset ns - clear the nameserver records | |
368 reset transfer - disable resource transfers | |
369 reset expiration - disable explicit expiration | |
370 reset value - clear the owner, description, password authentication and nameserver records | |
371 | |
372 Examples: | |
373 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 | |
374 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 | |
375 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 | |
376 OPEN marc.mdb SYNC http://marc.ucis.ano/ SAVE | |
377 '; | |
378 } |