| [2] | 1 | web frontend: | 
|---|
|  | 2 |  | 
|---|
|  | 3 | workflow: | 
|---|
|  | 4 |  | 
|---|
|  | 5 | log in, see domain list from current group | 
|---|
|  | 6 |  | 
|---|
|  | 7 | -> "current group" includes all subgroups?  (hairy SQL) | 
|---|
|  | 8 |  | 
|---|
|  | 9 |  | 
|---|
|  | 10 | logic: | 
|---|
|  | 11 | -> need to pass session ID on every call, otherwise we don't know who we are | 
|---|
|  | 12 | -> should check ACLs on every call in case of changing permissions | 
|---|
|  | 13 | -> should be able to store all webvar bits in the session | 
|---|
|  | 14 |  | 
|---|
|  | 15 |  | 
|---|
|  | 16 | ooo! ooo!  what about "clone existing domain"? | 
|---|
|  | 17 |  | 
|---|
|  | 18 |  | 
|---|
| [81] | 19 | export for tinydns:  arbitrary record data is binary blob, decomposed by hex octets to octal codes | 
|---|
|  | 20 |  | 
|---|
|  | 21 |  | 
|---|
| [2] | 22 | components: | 
|---|
|  | 23 | menu list (actions/sections) | 
|---|
|  | 24 | domain list | 
|---|
|  | 25 | group tree | 
|---|
|  | 26 | user list | 
|---|
|  | 27 | <various edit <entity> pages> | 
|---|
|  | 28 |  | 
|---|
|  | 29 |  | 
|---|
|  | 30 |  | 
|---|
|  | 31 | time tables: | 
|---|
|  | 32 | 3600: 1h | 
|---|
|  | 33 | 7200: 2h | 
|---|
|  | 34 | 10800: 3h | 
|---|
|  | 35 | 14400: 4h | 
|---|
|  | 36 | 21600: 6h | 
|---|
|  | 37 | 43200: 12h | 
|---|
|  | 38 | 86400: 1d | 
|---|
|  | 39 | 172800: 2d | 
|---|
|  | 40 | 604800: 7d (1w) | 
|---|
|  | 41 |  | 
|---|
|  | 42 | valid records: | 
|---|
|  | 43 |  | 
|---|
|  | 44 | nb:  wildcards are supported for most types.  use with extreme caution!  (I don't plan on writing | 
|---|
|  | 45 | tools that will create them.) | 
|---|
|  | 46 |  | 
|---|
|  | 47 | .fqdn:ip:x:ttl:timestamp:lo | 
|---|
|  | 48 | -> x.fqdn is a nameserver at ip, SOA sets x.fqdn as master with hostmaster@fqdn as contact | 
|---|
|  | 49 | -> if x contains a . that is used as the NS name | 
|---|
|  | 50 | (Not much use for us) | 
|---|
|  | 51 |  | 
|---|
|  | 52 | Zfqdn:primary:contact:serial:refresh:retry:expire:minttl:recttl:(timestamp:lo) | 
|---|
|  | 53 | -> SOA for fqdn | 
|---|
|  | 54 |  | 
|---|
|  | 55 | &fqdn:ip:x:ttl:timestamp:lo | 
|---|
|  | 56 | -> x.fqdn is a nameserver | 
|---|
|  | 57 | -> if x contains a . that is used as the NS name | 
|---|
|  | 58 | -> ip may be omitted;  A record for fqdn->ip is created otherwise | 
|---|
|  | 59 |  | 
|---|
|  | 60 | =fqdn:ip:ttl:timestamp:lo | 
|---|
|  | 61 | -> A record and matching PTR record with fqdn and ip | 
|---|
|  | 62 |  | 
|---|
|  | 63 | +fqdn:ip:ttl:timestamp:lo | 
|---|
|  | 64 | -> A record | 
|---|
|  | 65 |  | 
|---|
|  | 66 | ^ptr:fqdn:ttl:timestamp:lo | 
|---|
|  | 67 | -> PTR record.  note ptr must be reverse-IP format ending in .in-addr.arpa | 
|---|
|  | 68 |  | 
|---|
|  | 69 | @fqdn:ip:x:dist:ttl:timestamp:lo | 
|---|
|  | 70 | -> MX.  Dist defaults to 0. | 
|---|
|  | 71 | -> ip may be omitted;  A record for fqdn->ip is created otherwise | 
|---|
|  | 72 |  | 
|---|
|  | 73 | -fqdn:ip:ttl:timestamp:lo | 
|---|
|  | 74 | -> ignored | 
|---|
|  | 75 |  | 
|---|
|  | 76 | 'fqdn:text:ttl:timestamp:lo | 
|---|
|  | 77 | -> TXT record | 
|---|
|  | 78 | -> octal-encode special characters in text as \nnn | 
|---|
|  | 79 |  | 
|---|
|  | 80 | Cfqdn:name:ttl:timestamp:lo | 
|---|
|  | 81 | -> CNAME for fqdn pointing to name | 
|---|
|  | 82 |  | 
|---|
|  | 83 | :fqdn:n:data:ttl:timestamp:lo | 
|---|
|  | 84 | -> Generic data, of type n (n is a 16-bit unsigned integer) | 
|---|
|  | 85 | 17 is RP | 
|---|
|  | 86 | 16 is TXT | 
|---|
|  | 87 | 2 (NS), 5 (CNAME), 6 (SOA), 12 (PTR), 15 (MX) and 252 (AXFR) (WTF?) should not be used | 
|---|
|  | 88 | -> data must use octal escapes for : or nondisplayable characters.  axfr-get seems to escape all | 
|---|
|  | 89 | non-alphanumerics, therefore so will we. | 
|---|
|  | 90 |  | 
|---|
|  | 91 | two primary groups of data: | 
|---|
|  | 92 | -> forward zones | 
|---|
|  | 93 | -> local master zones | 
|---|
|  | 94 | -> local slave zones | 
|---|
|  | 95 | -> reverse zones | 
|---|
|  | 96 | - note that it would be really nice to eliminate duplicated A records (+domain.com:ip:: plus =domain.com:ip::) | 
|---|
|  | 97 |  | 
|---|
|  | 98 | operations: | 
|---|
|  | 99 | -> import zone data (BIND*, djbdns, vegadns-mysql) | 
|---|
|  | 100 | -> allow overwrite of existing SOA | 
|---|
|  | 101 | -> export data (BIND*, djbdns) | 
|---|
|  | 102 | -> add zone/domain | 
|---|
|  | 103 | -> as slave | 
|---|
|  | 104 | -> as master | 
|---|
|  | 105 | -> delete zone/domain | 
|---|
|  | 106 | -> add record to domain | 
|---|
|  | 107 | -> remove record from domain | 
|---|
|  | 108 | -> change record | 
|---|
|  | 109 | -> A record IP | 
|---|
|  | 110 | -> CNAME destination | 
|---|
|  | 111 | -> MX destination | 
|---|
|  | 112 | -> MX priority | 
|---|
|  | 113 | -> A <-> CNAME ? | 
|---|
|  | 114 | -> flag record as "primary" A record for an IP (means that PTR will set that name as rDNS) | 
|---|
|  | 115 | -> force propagation (execute propagation script) | 
|---|
|  | 116 | -> User ACL fiddling: | 
|---|
|  | 117 | -> take IPDB model, include groups/delegation/etc | 
|---|
|  | 118 | "admin" -> nominally full access to anything/everything | 
|---|
|  | 119 | "staff" -> general access to all domains, can create users and delegate domains to them | 
|---|
|  | 120 | "bulk hoster" -> customer with more than one domain, (can create users and delegate domains to them)? | 
|---|
|  | 121 | "user" -> customer with one domain | 
|---|
|  | 122 |  | 
|---|
|  | 123 |  | 
|---|
|  | 124 | recommended SOA/TTL/etc times: | 
|---|
|  | 125 | refresh 86400 (24h), retry 7200 (2h), expire 2592000 (30d), ttl 345600 (4d) | 
|---|
|  | 126 |  | 
|---|
|  | 127 | Qs re: new servers: | 
|---|
|  | 128 | -> IPs for cache/authoritative? | 
|---|
|  | 129 |  | 
|---|
|  | 130 |  | 
|---|
|  | 131 | flow of data: | 
|---|
|  | 132 | user input -> database -> local "zone" data -> rsync/scp to slaves | 
|---|
|  | 133 |  | 
|---|
|  | 134 | don't use "domain ID" goop;  its only advantage is slightly lower disk use.  otherwise it's more | 
|---|
|  | 135 | complicated, less traceable thru the DB manually | 
|---|
|  | 136 |  | 
|---|
|  | 137 |  | 
|---|
|  | 138 | db structure (current) | 
|---|
|  | 139 |  | 
|---|
|  | 140 | domains: | 
|---|
|  | 141 | | domain_id   | int(11)                   |      | MUL | NULL     | auto_increment | | 
|---|
|  | 142 | | domain      | varchar(100)              |      |     |          |                | | 
|---|
|  | 143 | | group_id    | int(11)                   | YES  |     | NULL     |                | | 
|---|
|  | 144 | | description | varchar(255)              |      |     |          |                | | 
|---|
|  | 145 | | status      | enum('active','inactive') |      |     | inactive |                | | 
|---|
|  | 146 |  | 
|---|
|  | 147 | records: | 
|---|
|  | 148 | | domain_id   | int(11)      |      | MUL | 0       |                | | 
|---|
|  | 149 | | record_id   | int(11)      |      | PRI | NULL    | auto_increment | | 
|---|
|  | 150 | | host        | varchar(100) |      |     |         |                | | 
|---|
|  | 151 | | type        | char(1)      | YES  |     | NULL    |                | | 
|---|
|  | 152 | | val         | varchar(100) | YES  |     | NULL    |                | | 
|---|
|  | 153 | | distance    | int(4)       | YES  |     | 0       |                | | 
|---|
|  | 154 | | weight      | int(4)       | YES  |     | NULL    |                | - for SRV only | 
|---|
|  | 155 | | port        | int(4)       | YES  |     | NULL    |                | - for SRV only | 
|---|
|  | 156 | | ttl         | int(11)      |      |     | 86400   |                | | 
|---|
|  | 157 | | description | varchar(255) |      |     |         |                | | 
|---|
|  | 158 |  | 
|---|
|  | 159 | default_records is a duplicate of records structurally | 
|---|
|  | 160 |  | 
|---|
|  | 161 | log:  (not sure how useful this really is, in this form...) | 
|---|
|  | 162 | | domain_id | int(11)      |      |     | 0       |       | | 
|---|
|  | 163 | | user_id   | int(11)      |      |     | 0       |       | | 
|---|
|  | 164 | | group_id  | int(11)      |      |     | 0       |       | | 
|---|
|  | 165 | | email     | varchar(60)  |      |     |         |       | | 
|---|
|  | 166 | | name      | varchar(60)  |      |     |         |       | | 
|---|
|  | 167 | | entry     | varchar(200) |      |     |         |       | | 
|---|
|  | 168 | | time      | int(11)      |      |     | 0       |       | | 
|---|
|  | 169 |  | 
|---|
|  | 170 | db structure (proposed) | 
|---|
|  | 171 |  | 
|---|
|  | 172 | domains: | 
|---|
|  | 173 | domain  char(128)       pk, indexed | 
|---|
|  | 174 | group   char(32)        fk, indexed? | 
|---|
|  | 175 | status  enum? | 
|---|
|  | 176 | masterns char(64) | 
|---|
|  | 177 | email   char(128) | 
|---|
|  | 178 | serial  long int (needs 2^32 at least) | 
|---|
|  | 179 | refresh long int        needs semi-sane default | 
|---|
|  | 180 | retry   long int        needs semi-sane default | 
|---|
|  | 181 | expire  long int        needs semi-sane default | 
|---|
|  | 182 | minttl  long int        needs semi-sane default | 
|---|
|  | 183 | ctime   timestamp | 
|---|
|  | 184 | mtime   timestamp | 
|---|
|  | 185 |  | 
|---|
|  | 186 | records: | 
|---|
|  | 187 | recid   serial | 
|---|
|  | 188 | domain  char(128)       fk, indexed? | 
|---|
|  | 189 | host    char(128)       pk, indexed | 
|---|
|  | 190 | type    enum? | 
|---|
|  | 191 | val     char(256)       to allow for 255-char TXT records | 
|---|
|  | 192 | extra   char(10)        10 should be enough to express any needs for MX, SRV, or anything else...right? | 
|---|
|  | 193 | ttl     long int | 
|---|
|  | 194 | ctime   timestamp | 
|---|
|  | 195 | mtime   timestamp | 
|---|
|  | 196 |  | 
|---|
|  | 197 | default records to be either database-coded as default values or coded in er, code. | 
|---|
|  | 198 | -> hrm. | 
|---|
|  | 199 | database-level defaults are "recommended practice" according to the cricket book | 
|---|
|  | 200 | code-level defaults may be hardcoded (easy) or loaded from a config file (harder, but cleaner) | 
|---|
|  | 201 | all must be overrideable by a database-table-stored "local policy defaults" widget | 
|---|
|  | 202 |  | 
|---|
|  | 203 | add domain: | 
|---|
|  | 204 | -> need domain name | 
|---|
|  | 205 | -> IP/"company default" radio button pair, with some Javascript to change defaults for: | 
|---|
|  | 206 | -> radio buttons with sane defaults for standard hosts (www/mail/ftp/smtp) | 
|---|
|  | 207 | -> www CNAME @ | 
|---|
|  | 208 | -> FTP CNAME @ | 
|---|
|  | 209 | -> mail CNAME mail.company.com | 
|---|
|  | 210 | -> smtp CNAME smtp.company.com | 
|---|
|  | 211 | -> MX defaults to <mxlist> | 
|---|
|  | 212 |  | 
|---|
|  | 213 | +----------------------------------------------------------------+ | 
|---|
|  | 214 | | Domain: _________________________________                      | | 
|---|
|  | 215 | | o Company hosting       o Slave zone        o Custom settings  | | 
|---|
|  | 216 | +----------------------------------------------------------------+ | 
|---|
|  | 217 |  | 
|---|
|  | 218 | add_domain($domain,$class) | 
|---|
|  | 219 | update_domain($domain,$group,$status,[$contact,$primary,$serial,$ttl,$refresh,$retry,$expire,$minttl]) | 
|---|
|  | 220 | delete_domain($domain) | 
|---|
|  | 221 | lock_domain($domain)  -hm..  lock/unlock may be admin-level "don't touch!" flags vs "active/inactive" flags | 
|---|
|  | 222 | unlock_domain($domain) | 
|---|
|  | 223 | add_record($domain,$host,$type,$value,$extra,$ttl) | 
|---|
|  | 224 | update_record($id,$host,$type,$val,$extra,$ttl) | 
|---|
|  | 225 | delete_record($id) | 
|---|
|  | 226 | export_data($domain,$format) ->takes special <ALL> arg for all zones.  $format -> BIND or djb (implement DJB first) | 
|---|
|  | 227 | update_nameservers() | 
|---|
|  | 228 |  | 
|---|
| [39] | 229 |  | 
|---|
|  | 230 | FFFF:FFFF:FFFF:FFFF : FFFF:FFFF:FFFF:FFFF | 
|---|
|  | 231 | we get: | 
|---|
|  | 232 | <x>:<x>:FFFF:FFFF | 
|---|
|  | 233 | we assign: | 
|---|
|  | 234 | <x>:<x>:<y>:<a>       (/64, nominally equivalent to current /32, logically) | 
|---|
|  | 235 | <x>:<x>:<y>:<b>FF     (/56, bitwise equivalent to current /24 relative to /32) | 
|---|
|  | 236 | <x>:<x>:<y>:FFFF      (/48, bitwise equivalent to current /16 relative to /24) | 
|---|
|  | 237 |  | 
|---|
|  | 238 | Allocations SHOULD leave space for growth | 
|---|
|  | 239 |  | 
|---|
|  | 240 |  | 
|---|
|  | 241 | SELECT u.user_id, u.email, u.firstname, u.lastname, u.type, g.group_name | 
|---|
|  | 242 | "FROM users u ". | 
|---|
|  | 243 | "INNER JOIN groups g ON u.group_id=g.group_id ". | 
|---|
|  | 244 | ($offset eq 'all' ? '' : " LIMIT $perpage OFFSET ".$offset*$perpage) | 
|---|
|  | 245 |  | 
|---|
|  | 246 |  | 
|---|
|  | 247 | SELECT g.group_id, g.group_name, g2.group_name, g.children, count(distinct(u.email)), count(distinct(d.domain)) | 
|---|
|  | 248 | FROM groups g | 
|---|
|  | 249 | INNER JOIN groups g2 ON g2.group_id=g.parent_group_id | 
|---|
|  | 250 | LEFT OUTER JOIN users u ON u.group_id=g.group_id | 
|---|
|  | 251 | LEFT OUTER JOIN domains d ON d.group_id=g.group_id | 
|---|
|  | 252 | GROUP BY g.group_id, g.group_name, g2.group_name, g.children | 
|---|
|  | 253 |  | 
|---|
|  | 254 |  | 
|---|
|  | 255 |  | 
|---|
|  | 256 | record_id | group_id |                  host                  | type |           val           | distance | weight | port |  ttl  | description | 
|---|
|  | 257 | -----------+----------+----------------------------------------+------+-------------------------+----------+--------+------+-------+------------- | 
|---|
|  | 258 | 1 |        1 | ns1.example.com:hostmaster.DOMAIN      |    6 | 10800:3600:604800:10800 |        0 |      0 |    0 | 86400 | | 
|---|
|  | 259 | 25 |        1 | DOMAIN                                 |    1 | 10.2.3.4                |        0 |      0 |    0 |  7200 | | 
|---|
|  | 260 | 2 |        1 | DOMAIN                                 |   15 | mx1.example.com         |       10 |      0 |    0 |  7200 | | 
|---|
|  | 261 | 26 |        1 | DOMAIN                                 |   15 | mx2.example.com         |       10 |      0 |    0 |  7200 | | 
|---|
|  | 262 | 27 |        1 | DOMAIN                                 |    2 | ns2.example.com         |        0 |      0 |    0 |  7200 | | 
|---|
|  | 263 | 22 |        1 | DOMAIN                                 |    2 | ns1.example.com         |        0 |      0 |    0 |  7200 | | 
|---|
|  | 264 | 31 |        1 | www.DOMAIN                             |    5 | DOMAIN                  |        0 |      0 |    0 | 10800 | | 
|---|
|  | 265 | 32 |        1 | DOMAIN                                 |   16 | "v=spf1 a mx -all"      |        0 |      0 |    0 | 10800 | | 
|---|
|  | 266 | 17 |        1 | DOMAIN                                 |   33 | srv.example.com         |       15 |      2 |  325 |  7200 | | 
|---|
|  | 267 |  | 
|---|
|  | 268 |  | 
|---|
|  | 269 | serial in domains table | 
|---|
|  | 270 | 'manual' - date+inc | 
|---|
|  | 271 | 'manual' - monotone | 
|---|
|  | 272 | 'auto' - generated (TinyDNS only;  uses auto(date) for other exports) | 
|---|
|  | 273 |  | 
|---|
| [81] | 274 | add enable/disable for individual records | 
|---|
| [39] | 275 |  | 
|---|
|  | 276 | log_id?  domain_id?  group_id  user_id  action  detail timestamp | 
|---|
| [81] | 277 |  | 
|---|
|  | 278 |  | 
|---|
|  | 279 |  | 
|---|
|  | 280 | LOG_EMERG | 
|---|
|  | 281 | A panic condition. | 
|---|
|  | 282 |  | 
|---|
|  | 283 | LOG_ALERT | 
|---|
|  | 284 | A condition that should be corrected immediately, such as a corrupted system database. | 
|---|
|  | 285 |  | 
|---|
|  | 286 | LOG_CRIT | 
|---|
|  | 287 | Critical conditions, such as hard device errors. | 
|---|
|  | 288 |  | 
|---|
|  | 289 | LOG_ERR | 
|---|
|  | 290 | Errors. | 
|---|
|  | 291 |  | 
|---|
|  | 292 | LOG_WARNING | 
|---|
|  | 293 |  | 
|---|
|  | 294 | Warning messages. | 
|---|
|  | 295 |  | 
|---|
|  | 296 | LOG_NOTICE | 
|---|
|  | 297 | Conditions that are not error conditions, but that may require special handling. | 
|---|
|  | 298 |  | 
|---|
|  | 299 | LOG_INFO | 
|---|
|  | 300 | Informational messages. | 
|---|
|  | 301 |  | 
|---|
|  | 302 | LOG_DEBUG | 
|---|
|  | 303 | #define LOG_EMERG       0       /* system is unusable */ | 
|---|
|  | 304 | #define LOG_ALERT       1       /* action must be taken immediately */ | 
|---|
|  | 305 | #define LOG_CRIT        2       /* critical conditions */ | 
|---|
|  | 306 | #define LOG_ERR         3       /* error conditions */ | 
|---|
|  | 307 | #define LOG_WARNING     4       /* warning conditions */ | 
|---|
|  | 308 | #define LOG_NOTICE      5       /* normal but significant condition */ | 
|---|
|  | 309 | #define LOG_INFO        6       /* informational */ | 
|---|
|  | 310 | #define LOG_DEBUG       7       /* debug-level messages */ | 
|---|
| [545] | 311 |  | 
|---|
|  | 312 |  | 
|---|
|  | 313 |  | 
|---|
|  | 314 | another web-UI for DNS record maintenance: | 
|---|
|  | 315 | http://www.henriknordstrom.net/code/webdns/ | 
|---|
|  | 316 |  | 
|---|
|  | 317 |  | 
|---|
|  | 318 | sub-octet delegation for v4 nets: | 
|---|
|  | 319 | p 216-218 in cricket^Wgrasshopper book | 
|---|
|  | 320 |  | 
|---|
|  | 321 | Also see new draft spec, applies to both v4 and v6: | 
|---|
|  | 322 | http://tools.ietf.org/html/draft-gersch-dnsop-revdns-cidr-01 | 
|---|
|  | 323 |  | 
|---|
|  | 324 | new custom types "Forward delegation" and "Reverse delegation"? | 
|---|
|  | 325 | - forward creates NS records in parent for <sub>.parent | 
|---|
|  | 326 | - reverse creates NS records plus CNAMEs for sub-octet zones | 
|---|
|  | 327 | -> would solve the conundrum of what to do with the unsightly CNAME | 
|---|
|  | 328 | records presented in the UI to indicate sub-octet zone delegation | 
|---|