384 lines
8.7 KiB
Go
384 lines
8.7 KiB
Go
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
// +build ignore
|
||
|
|
||
|
//go:generate go run gen.go
|
||
|
|
||
|
// This program generates internet protocol constants and tables by
|
||
|
// reading IANA protocol registries.
|
||
|
package main
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/xml"
|
||
|
"fmt"
|
||
|
"go/format"
|
||
|
"io"
|
||
|
"io/ioutil"
|
||
|
"net/http"
|
||
|
"os"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
var registries = []struct {
|
||
|
url string
|
||
|
parse func(io.Writer, io.Reader) error
|
||
|
}{
|
||
|
{
|
||
|
"https://www.iana.org/assignments/dscp-registry/dscp-registry.xml",
|
||
|
parseDSCPRegistry,
|
||
|
},
|
||
|
{
|
||
|
"https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml",
|
||
|
parseProtocolNumbers,
|
||
|
},
|
||
|
{
|
||
|
"https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml",
|
||
|
parseAddrFamilyNumbers,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
var bb bytes.Buffer
|
||
|
fmt.Fprintf(&bb, "// go generate gen.go\n")
|
||
|
fmt.Fprintf(&bb, "// Code generated by the command above; DO NOT EDIT.\n\n")
|
||
|
fmt.Fprintf(&bb, "// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).\n")
|
||
|
fmt.Fprintf(&bb, `package iana // import "golang.org/x/net/internal/iana"`+"\n\n")
|
||
|
for _, r := range registries {
|
||
|
resp, err := http.Get(r.url)
|
||
|
if err != nil {
|
||
|
fmt.Fprintln(os.Stderr, err)
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
if resp.StatusCode != http.StatusOK {
|
||
|
fmt.Fprintf(os.Stderr, "got HTTP status code %v for %v\n", resp.StatusCode, r.url)
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
if err := r.parse(&bb, resp.Body); err != nil {
|
||
|
fmt.Fprintln(os.Stderr, err)
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
fmt.Fprintf(&bb, "\n")
|
||
|
}
|
||
|
b, err := format.Source(bb.Bytes())
|
||
|
if err != nil {
|
||
|
fmt.Fprintln(os.Stderr, err)
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
if err := ioutil.WriteFile("const.go", b, 0644); err != nil {
|
||
|
fmt.Fprintln(os.Stderr, err)
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func parseDSCPRegistry(w io.Writer, r io.Reader) error {
|
||
|
dec := xml.NewDecoder(r)
|
||
|
var dr dscpRegistry
|
||
|
if err := dec.Decode(&dr); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
fmt.Fprintf(w, "// %s, Updated: %s\n", dr.Title, dr.Updated)
|
||
|
fmt.Fprintf(w, "const (\n")
|
||
|
for _, dr := range dr.escapeDSCP() {
|
||
|
fmt.Fprintf(w, "DiffServ%s = %#02x", dr.Name, dr.Value)
|
||
|
fmt.Fprintf(w, "// %s\n", dr.OrigName)
|
||
|
}
|
||
|
for _, er := range dr.escapeECN() {
|
||
|
fmt.Fprintf(w, "%s = %#02x", er.Descr, er.Value)
|
||
|
fmt.Fprintf(w, "// %s\n", er.OrigDescr)
|
||
|
}
|
||
|
fmt.Fprintf(w, ")\n")
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
type dscpRegistry struct {
|
||
|
XMLName xml.Name `xml:"registry"`
|
||
|
Title string `xml:"title"`
|
||
|
Updated string `xml:"updated"`
|
||
|
Note string `xml:"note"`
|
||
|
Registries []struct {
|
||
|
Title string `xml:"title"`
|
||
|
Registries []struct {
|
||
|
Title string `xml:"title"`
|
||
|
Records []struct {
|
||
|
Name string `xml:"name"`
|
||
|
Space string `xml:"space"`
|
||
|
} `xml:"record"`
|
||
|
} `xml:"registry"`
|
||
|
Records []struct {
|
||
|
Value string `xml:"value"`
|
||
|
Descr string `xml:"description"`
|
||
|
} `xml:"record"`
|
||
|
} `xml:"registry"`
|
||
|
}
|
||
|
|
||
|
type canonDSCPRecord struct {
|
||
|
OrigName string
|
||
|
Name string
|
||
|
Value int
|
||
|
}
|
||
|
|
||
|
func (drr *dscpRegistry) escapeDSCP() []canonDSCPRecord {
|
||
|
var drs []canonDSCPRecord
|
||
|
for _, preg := range drr.Registries {
|
||
|
if !strings.Contains(preg.Title, "Differentiated Services Field Codepoints") {
|
||
|
continue
|
||
|
}
|
||
|
for _, reg := range preg.Registries {
|
||
|
if !strings.Contains(reg.Title, "Pool 1 Codepoints") {
|
||
|
continue
|
||
|
}
|
||
|
drs = make([]canonDSCPRecord, len(reg.Records))
|
||
|
sr := strings.NewReplacer(
|
||
|
"+", "",
|
||
|
"-", "",
|
||
|
"/", "",
|
||
|
".", "",
|
||
|
" ", "",
|
||
|
)
|
||
|
for i, dr := range reg.Records {
|
||
|
s := strings.TrimSpace(dr.Name)
|
||
|
drs[i].OrigName = s
|
||
|
drs[i].Name = sr.Replace(s)
|
||
|
n, err := strconv.ParseUint(dr.Space, 2, 8)
|
||
|
if err != nil {
|
||
|
continue
|
||
|
}
|
||
|
drs[i].Value = int(n) << 2
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return drs
|
||
|
}
|
||
|
|
||
|
type canonECNRecord struct {
|
||
|
OrigDescr string
|
||
|
Descr string
|
||
|
Value int
|
||
|
}
|
||
|
|
||
|
func (drr *dscpRegistry) escapeECN() []canonECNRecord {
|
||
|
var ers []canonECNRecord
|
||
|
for _, reg := range drr.Registries {
|
||
|
if !strings.Contains(reg.Title, "ECN Field") {
|
||
|
continue
|
||
|
}
|
||
|
ers = make([]canonECNRecord, len(reg.Records))
|
||
|
sr := strings.NewReplacer(
|
||
|
"Capable", "",
|
||
|
"Not-ECT", "",
|
||
|
"ECT(1)", "",
|
||
|
"ECT(0)", "",
|
||
|
"CE", "",
|
||
|
"(", "",
|
||
|
")", "",
|
||
|
"+", "",
|
||
|
"-", "",
|
||
|
"/", "",
|
||
|
".", "",
|
||
|
" ", "",
|
||
|
)
|
||
|
for i, er := range reg.Records {
|
||
|
s := strings.TrimSpace(er.Descr)
|
||
|
ers[i].OrigDescr = s
|
||
|
ss := strings.Split(s, " ")
|
||
|
if len(ss) > 1 {
|
||
|
ers[i].Descr = strings.Join(ss[1:], " ")
|
||
|
} else {
|
||
|
ers[i].Descr = ss[0]
|
||
|
}
|
||
|
ers[i].Descr = sr.Replace(er.Descr)
|
||
|
n, err := strconv.ParseUint(er.Value, 2, 8)
|
||
|
if err != nil {
|
||
|
continue
|
||
|
}
|
||
|
ers[i].Value = int(n)
|
||
|
}
|
||
|
}
|
||
|
return ers
|
||
|
}
|
||
|
|
||
|
func parseProtocolNumbers(w io.Writer, r io.Reader) error {
|
||
|
dec := xml.NewDecoder(r)
|
||
|
var pn protocolNumbers
|
||
|
if err := dec.Decode(&pn); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
prs := pn.escape()
|
||
|
prs = append([]canonProtocolRecord{{
|
||
|
Name: "IP",
|
||
|
Descr: "IPv4 encapsulation, pseudo protocol number",
|
||
|
Value: 0,
|
||
|
}}, prs...)
|
||
|
fmt.Fprintf(w, "// %s, Updated: %s\n", pn.Title, pn.Updated)
|
||
|
fmt.Fprintf(w, "const (\n")
|
||
|
for _, pr := range prs {
|
||
|
if pr.Name == "" {
|
||
|
continue
|
||
|
}
|
||
|
fmt.Fprintf(w, "Protocol%s = %d", pr.Name, pr.Value)
|
||
|
s := pr.Descr
|
||
|
if s == "" {
|
||
|
s = pr.OrigName
|
||
|
}
|
||
|
fmt.Fprintf(w, "// %s\n", s)
|
||
|
}
|
||
|
fmt.Fprintf(w, ")\n")
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
type protocolNumbers struct {
|
||
|
XMLName xml.Name `xml:"registry"`
|
||
|
Title string `xml:"title"`
|
||
|
Updated string `xml:"updated"`
|
||
|
RegTitle string `xml:"registry>title"`
|
||
|
Note string `xml:"registry>note"`
|
||
|
Records []struct {
|
||
|
Value string `xml:"value"`
|
||
|
Name string `xml:"name"`
|
||
|
Descr string `xml:"description"`
|
||
|
} `xml:"registry>record"`
|
||
|
}
|
||
|
|
||
|
type canonProtocolRecord struct {
|
||
|
OrigName string
|
||
|
Name string
|
||
|
Descr string
|
||
|
Value int
|
||
|
}
|
||
|
|
||
|
func (pn *protocolNumbers) escape() []canonProtocolRecord {
|
||
|
prs := make([]canonProtocolRecord, len(pn.Records))
|
||
|
sr := strings.NewReplacer(
|
||
|
"-in-", "in",
|
||
|
"-within-", "within",
|
||
|
"-over-", "over",
|
||
|
"+", "P",
|
||
|
"-", "",
|
||
|
"/", "",
|
||
|
".", "",
|
||
|
" ", "",
|
||
|
)
|
||
|
for i, pr := range pn.Records {
|
||
|
if strings.Contains(pr.Name, "Deprecated") ||
|
||
|
strings.Contains(pr.Name, "deprecated") {
|
||
|
continue
|
||
|
}
|
||
|
prs[i].OrigName = pr.Name
|
||
|
s := strings.TrimSpace(pr.Name)
|
||
|
switch pr.Name {
|
||
|
case "ISIS over IPv4":
|
||
|
prs[i].Name = "ISIS"
|
||
|
case "manet":
|
||
|
prs[i].Name = "MANET"
|
||
|
default:
|
||
|
prs[i].Name = sr.Replace(s)
|
||
|
}
|
||
|
ss := strings.Split(pr.Descr, "\n")
|
||
|
for i := range ss {
|
||
|
ss[i] = strings.TrimSpace(ss[i])
|
||
|
}
|
||
|
if len(ss) > 1 {
|
||
|
prs[i].Descr = strings.Join(ss, " ")
|
||
|
} else {
|
||
|
prs[i].Descr = ss[0]
|
||
|
}
|
||
|
prs[i].Value, _ = strconv.Atoi(pr.Value)
|
||
|
}
|
||
|
return prs
|
||
|
}
|
||
|
|
||
|
func parseAddrFamilyNumbers(w io.Writer, r io.Reader) error {
|
||
|
dec := xml.NewDecoder(r)
|
||
|
var afn addrFamilylNumbers
|
||
|
if err := dec.Decode(&afn); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
afrs := afn.escape()
|
||
|
fmt.Fprintf(w, "// %s, Updated: %s\n", afn.Title, afn.Updated)
|
||
|
fmt.Fprintf(w, "const (\n")
|
||
|
for _, afr := range afrs {
|
||
|
if afr.Name == "" {
|
||
|
continue
|
||
|
}
|
||
|
fmt.Fprintf(w, "AddrFamily%s = %d", afr.Name, afr.Value)
|
||
|
fmt.Fprintf(w, "// %s\n", afr.Descr)
|
||
|
}
|
||
|
fmt.Fprintf(w, ")\n")
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
type addrFamilylNumbers struct {
|
||
|
XMLName xml.Name `xml:"registry"`
|
||
|
Title string `xml:"title"`
|
||
|
Updated string `xml:"updated"`
|
||
|
RegTitle string `xml:"registry>title"`
|
||
|
Note string `xml:"registry>note"`
|
||
|
Records []struct {
|
||
|
Value string `xml:"value"`
|
||
|
Descr string `xml:"description"`
|
||
|
} `xml:"registry>record"`
|
||
|
}
|
||
|
|
||
|
type canonAddrFamilyRecord struct {
|
||
|
Name string
|
||
|
Descr string
|
||
|
Value int
|
||
|
}
|
||
|
|
||
|
func (afn *addrFamilylNumbers) escape() []canonAddrFamilyRecord {
|
||
|
afrs := make([]canonAddrFamilyRecord, len(afn.Records))
|
||
|
sr := strings.NewReplacer(
|
||
|
"IP version 4", "IPv4",
|
||
|
"IP version 6", "IPv6",
|
||
|
"Identifier", "ID",
|
||
|
"-", "",
|
||
|
"-", "",
|
||
|
"/", "",
|
||
|
".", "",
|
||
|
" ", "",
|
||
|
)
|
||
|
for i, afr := range afn.Records {
|
||
|
if strings.Contains(afr.Descr, "Unassigned") ||
|
||
|
strings.Contains(afr.Descr, "Reserved") {
|
||
|
continue
|
||
|
}
|
||
|
afrs[i].Descr = afr.Descr
|
||
|
s := strings.TrimSpace(afr.Descr)
|
||
|
switch s {
|
||
|
case "IP (IP version 4)":
|
||
|
afrs[i].Name = "IPv4"
|
||
|
case "IP6 (IP version 6)":
|
||
|
afrs[i].Name = "IPv6"
|
||
|
case "AFI for L2VPN information":
|
||
|
afrs[i].Name = "L2VPN"
|
||
|
case "E.164 with NSAP format subaddress":
|
||
|
afrs[i].Name = "E164withSubaddress"
|
||
|
case "MT IP: Multi-Topology IP version 4":
|
||
|
afrs[i].Name = "MTIPv4"
|
||
|
case "MAC/24":
|
||
|
afrs[i].Name = "MACFinal24bits"
|
||
|
case "MAC/40":
|
||
|
afrs[i].Name = "MACFinal40bits"
|
||
|
case "IPv6/64":
|
||
|
afrs[i].Name = "IPv6Initial64bits"
|
||
|
default:
|
||
|
n := strings.Index(s, "(")
|
||
|
if n > 0 {
|
||
|
s = s[:n]
|
||
|
}
|
||
|
n = strings.Index(s, ":")
|
||
|
if n > 0 {
|
||
|
s = s[:n]
|
||
|
}
|
||
|
afrs[i].Name = sr.Replace(s)
|
||
|
}
|
||
|
afrs[i].Value, _ = strconv.Atoi(afr.Value)
|
||
|
}
|
||
|
return afrs
|
||
|
}
|