github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/internal/iana/gen.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build ignore 6 7 //go:generate go run gen.go 8 9 // This program generates internet protocol constants and tables by 10 // reading IANA protocol registries. 11 package main 12 13 import ( 14 "bytes" 15 "encoding/xml" 16 "fmt" 17 "go/format" 18 "io" 19 "io/ioutil" 20 "net/http" 21 "os" 22 "strconv" 23 "strings" 24 ) 25 26 var registries = []struct { 27 url string 28 parse func(io.Writer, io.Reader) error 29 }{ 30 { 31 "https://www.iana.org/assignments/dscp-registry/dscp-registry.xml", 32 parseDSCPRegistry, 33 }, 34 { 35 "https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml", 36 parseProtocolNumbers, 37 }, 38 { 39 "https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml", 40 parseAddrFamilyNumbers, 41 }, 42 } 43 44 func main() { 45 var bb bytes.Buffer 46 fmt.Fprintf(&bb, "// go generate gen.go\n") 47 fmt.Fprintf(&bb, "// Code generated by the command above; DO NOT EDIT.\n\n") 48 fmt.Fprintf(&bb, "// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).\n") 49 fmt.Fprintf(&bb, `package iana // import "github.com/Andyfoo/golang/x/net/internal/iana"`+"\n\n") 50 for _, r := range registries { 51 resp, err := http.Get(r.url) 52 if err != nil { 53 fmt.Fprintln(os.Stderr, err) 54 os.Exit(1) 55 } 56 defer resp.Body.Close() 57 if resp.StatusCode != http.StatusOK { 58 fmt.Fprintf(os.Stderr, "got HTTP status code %v for %v\n", resp.StatusCode, r.url) 59 os.Exit(1) 60 } 61 if err := r.parse(&bb, resp.Body); err != nil { 62 fmt.Fprintln(os.Stderr, err) 63 os.Exit(1) 64 } 65 fmt.Fprintf(&bb, "\n") 66 } 67 b, err := format.Source(bb.Bytes()) 68 if err != nil { 69 fmt.Fprintln(os.Stderr, err) 70 os.Exit(1) 71 } 72 if err := ioutil.WriteFile("const.go", b, 0644); err != nil { 73 fmt.Fprintln(os.Stderr, err) 74 os.Exit(1) 75 } 76 } 77 78 func parseDSCPRegistry(w io.Writer, r io.Reader) error { 79 dec := xml.NewDecoder(r) 80 var dr dscpRegistry 81 if err := dec.Decode(&dr); err != nil { 82 return err 83 } 84 fmt.Fprintf(w, "// %s, Updated: %s\n", dr.Title, dr.Updated) 85 fmt.Fprintf(w, "const (\n") 86 for _, dr := range dr.escapeDSCP() { 87 fmt.Fprintf(w, "DiffServ%s = %#02x", dr.Name, dr.Value) 88 fmt.Fprintf(w, "// %s\n", dr.OrigName) 89 } 90 for _, er := range dr.escapeECN() { 91 fmt.Fprintf(w, "%s = %#02x", er.Descr, er.Value) 92 fmt.Fprintf(w, "// %s\n", er.OrigDescr) 93 } 94 fmt.Fprintf(w, ")\n") 95 return nil 96 } 97 98 type dscpRegistry struct { 99 XMLName xml.Name `xml:"registry"` 100 Title string `xml:"title"` 101 Updated string `xml:"updated"` 102 Note string `xml:"note"` 103 Registries []struct { 104 Title string `xml:"title"` 105 Registries []struct { 106 Title string `xml:"title"` 107 Records []struct { 108 Name string `xml:"name"` 109 Space string `xml:"space"` 110 } `xml:"record"` 111 } `xml:"registry"` 112 Records []struct { 113 Value string `xml:"value"` 114 Descr string `xml:"description"` 115 } `xml:"record"` 116 } `xml:"registry"` 117 } 118 119 type canonDSCPRecord struct { 120 OrigName string 121 Name string 122 Value int 123 } 124 125 func (drr *dscpRegistry) escapeDSCP() []canonDSCPRecord { 126 var drs []canonDSCPRecord 127 for _, preg := range drr.Registries { 128 if !strings.Contains(preg.Title, "Differentiated Services Field Codepoints") { 129 continue 130 } 131 for _, reg := range preg.Registries { 132 if !strings.Contains(reg.Title, "Pool 1 Codepoints") { 133 continue 134 } 135 drs = make([]canonDSCPRecord, len(reg.Records)) 136 sr := strings.NewReplacer( 137 "+", "", 138 "-", "", 139 "/", "", 140 ".", "", 141 " ", "", 142 ) 143 for i, dr := range reg.Records { 144 s := strings.TrimSpace(dr.Name) 145 drs[i].OrigName = s 146 drs[i].Name = sr.Replace(s) 147 n, err := strconv.ParseUint(dr.Space, 2, 8) 148 if err != nil { 149 continue 150 } 151 drs[i].Value = int(n) << 2 152 } 153 } 154 } 155 return drs 156 } 157 158 type canonECNRecord struct { 159 OrigDescr string 160 Descr string 161 Value int 162 } 163 164 func (drr *dscpRegistry) escapeECN() []canonECNRecord { 165 var ers []canonECNRecord 166 for _, reg := range drr.Registries { 167 if !strings.Contains(reg.Title, "ECN Field") { 168 continue 169 } 170 ers = make([]canonECNRecord, len(reg.Records)) 171 sr := strings.NewReplacer( 172 "Capable", "", 173 "Not-ECT", "", 174 "ECT(1)", "", 175 "ECT(0)", "", 176 "CE", "", 177 "(", "", 178 ")", "", 179 "+", "", 180 "-", "", 181 "/", "", 182 ".", "", 183 " ", "", 184 ) 185 for i, er := range reg.Records { 186 s := strings.TrimSpace(er.Descr) 187 ers[i].OrigDescr = s 188 ss := strings.Split(s, " ") 189 if len(ss) > 1 { 190 ers[i].Descr = strings.Join(ss[1:], " ") 191 } else { 192 ers[i].Descr = ss[0] 193 } 194 ers[i].Descr = sr.Replace(er.Descr) 195 n, err := strconv.ParseUint(er.Value, 2, 8) 196 if err != nil { 197 continue 198 } 199 ers[i].Value = int(n) 200 } 201 } 202 return ers 203 } 204 205 func parseProtocolNumbers(w io.Writer, r io.Reader) error { 206 dec := xml.NewDecoder(r) 207 var pn protocolNumbers 208 if err := dec.Decode(&pn); err != nil { 209 return err 210 } 211 prs := pn.escape() 212 prs = append([]canonProtocolRecord{{ 213 Name: "IP", 214 Descr: "IPv4 encapsulation, pseudo protocol number", 215 Value: 0, 216 }}, prs...) 217 fmt.Fprintf(w, "// %s, Updated: %s\n", pn.Title, pn.Updated) 218 fmt.Fprintf(w, "const (\n") 219 for _, pr := range prs { 220 if pr.Name == "" { 221 continue 222 } 223 fmt.Fprintf(w, "Protocol%s = %d", pr.Name, pr.Value) 224 s := pr.Descr 225 if s == "" { 226 s = pr.OrigName 227 } 228 fmt.Fprintf(w, "// %s\n", s) 229 } 230 fmt.Fprintf(w, ")\n") 231 return nil 232 } 233 234 type protocolNumbers struct { 235 XMLName xml.Name `xml:"registry"` 236 Title string `xml:"title"` 237 Updated string `xml:"updated"` 238 RegTitle string `xml:"registry>title"` 239 Note string `xml:"registry>note"` 240 Records []struct { 241 Value string `xml:"value"` 242 Name string `xml:"name"` 243 Descr string `xml:"description"` 244 } `xml:"registry>record"` 245 } 246 247 type canonProtocolRecord struct { 248 OrigName string 249 Name string 250 Descr string 251 Value int 252 } 253 254 func (pn *protocolNumbers) escape() []canonProtocolRecord { 255 prs := make([]canonProtocolRecord, len(pn.Records)) 256 sr := strings.NewReplacer( 257 "-in-", "in", 258 "-within-", "within", 259 "-over-", "over", 260 "+", "P", 261 "-", "", 262 "/", "", 263 ".", "", 264 " ", "", 265 ) 266 for i, pr := range pn.Records { 267 if strings.Contains(pr.Name, "Deprecated") || 268 strings.Contains(pr.Name, "deprecated") { 269 continue 270 } 271 prs[i].OrigName = pr.Name 272 s := strings.TrimSpace(pr.Name) 273 switch pr.Name { 274 case "ISIS over IPv4": 275 prs[i].Name = "ISIS" 276 case "manet": 277 prs[i].Name = "MANET" 278 default: 279 prs[i].Name = sr.Replace(s) 280 } 281 ss := strings.Split(pr.Descr, "\n") 282 for i := range ss { 283 ss[i] = strings.TrimSpace(ss[i]) 284 } 285 if len(ss) > 1 { 286 prs[i].Descr = strings.Join(ss, " ") 287 } else { 288 prs[i].Descr = ss[0] 289 } 290 prs[i].Value, _ = strconv.Atoi(pr.Value) 291 } 292 return prs 293 } 294 295 func parseAddrFamilyNumbers(w io.Writer, r io.Reader) error { 296 dec := xml.NewDecoder(r) 297 var afn addrFamilylNumbers 298 if err := dec.Decode(&afn); err != nil { 299 return err 300 } 301 afrs := afn.escape() 302 fmt.Fprintf(w, "// %s, Updated: %s\n", afn.Title, afn.Updated) 303 fmt.Fprintf(w, "const (\n") 304 for _, afr := range afrs { 305 if afr.Name == "" { 306 continue 307 } 308 fmt.Fprintf(w, "AddrFamily%s = %d", afr.Name, afr.Value) 309 fmt.Fprintf(w, "// %s\n", afr.Descr) 310 } 311 fmt.Fprintf(w, ")\n") 312 return nil 313 } 314 315 type addrFamilylNumbers struct { 316 XMLName xml.Name `xml:"registry"` 317 Title string `xml:"title"` 318 Updated string `xml:"updated"` 319 RegTitle string `xml:"registry>title"` 320 Note string `xml:"registry>note"` 321 Records []struct { 322 Value string `xml:"value"` 323 Descr string `xml:"description"` 324 } `xml:"registry>record"` 325 } 326 327 type canonAddrFamilyRecord struct { 328 Name string 329 Descr string 330 Value int 331 } 332 333 func (afn *addrFamilylNumbers) escape() []canonAddrFamilyRecord { 334 afrs := make([]canonAddrFamilyRecord, len(afn.Records)) 335 sr := strings.NewReplacer( 336 "IP version 4", "IPv4", 337 "IP version 6", "IPv6", 338 "Identifier", "ID", 339 "-", "", 340 "-", "", 341 "/", "", 342 ".", "", 343 " ", "", 344 ) 345 for i, afr := range afn.Records { 346 if strings.Contains(afr.Descr, "Unassigned") || 347 strings.Contains(afr.Descr, "Reserved") { 348 continue 349 } 350 afrs[i].Descr = afr.Descr 351 s := strings.TrimSpace(afr.Descr) 352 switch s { 353 case "IP (IP version 4)": 354 afrs[i].Name = "IPv4" 355 case "IP6 (IP version 6)": 356 afrs[i].Name = "IPv6" 357 case "AFI for L2VPN information": 358 afrs[i].Name = "L2VPN" 359 case "E.164 with NSAP format subaddress": 360 afrs[i].Name = "E164withSubaddress" 361 case "MT IP: Multi-Topology IP version 4": 362 afrs[i].Name = "MTIPv4" 363 case "MAC/24": 364 afrs[i].Name = "MACFinal24bits" 365 case "MAC/40": 366 afrs[i].Name = "MACFinal40bits" 367 case "IPv6/64": 368 afrs[i].Name = "IPv6Initial64bits" 369 default: 370 n := strings.Index(s, "(") 371 if n > 0 { 372 s = s[:n] 373 } 374 n = strings.Index(s, ":") 375 if n > 0 { 376 s = s[:n] 377 } 378 afrs[i].Name = sr.Replace(s) 379 } 380 afrs[i].Value, _ = strconv.Atoi(afr.Value) 381 } 382 return afrs 383 }