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