Skip to content

Commit 2e81563

Browse files
committed
game: filter private range
1 parent 5ec2fc1 commit 2e81563

File tree

3 files changed

+316
-1
lines changed

3 files changed

+316
-1
lines changed

external.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,6 @@ done <${input}
6161

6262
rm -f data/game && touch data/game
6363

64-
cat .tmp/game/*.txt | grep -v '#' >> data/game
64+
cat .tmp/game/*.txt | grep -v '#' | go run ./merge >> data/game
6565

6666
echo "[game] $(wc -l data/game | cut -d' ' -f1) records out"

merge/ipset.go

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"math/bits"
7+
"net"
8+
"sort"
9+
"strconv"
10+
)
11+
12+
func assert(condition bool, format string, args ...interface{}) {
13+
if !condition {
14+
panic(fmt.Sprintf("assert failed: "+format, args...))
15+
}
16+
}
17+
18+
func ipToString(ip net.IP) string {
19+
if len(ip) == net.IPv6len {
20+
if ipv4 := ip.To4(); len(ipv4) == net.IPv4len {
21+
return "::ffff:" + ipv4.String()
22+
}
23+
}
24+
return ip.String()
25+
}
26+
27+
type IRange interface {
28+
ToIp() net.IP // return nil if it can't be represented as a single ip
29+
ToIpNets() []*net.IPNet
30+
ToRange() *Range
31+
String() string
32+
}
33+
34+
type Range struct {
35+
start net.IP
36+
end net.IP
37+
}
38+
39+
func (r *Range) familyLength() int {
40+
return len(r.start)
41+
}
42+
func (r *Range) ToIp() net.IP {
43+
if net.IP.Equal(r.start, r.end) {
44+
return r.start
45+
}
46+
return nil
47+
}
48+
func (r *Range) ToIpNets() []*net.IPNet {
49+
s, end := r.start, r.end
50+
ipBits := len(s) * 8
51+
assert(ipBits == len(end)*8, "len(r.start) == len(r.end)")
52+
var result []*net.IPNet
53+
for {
54+
assert(bytes.Compare(s, end) <= 0, "s <= end")
55+
cidr := max(prefixLength(xor(addOne(end), s)), ipBits-trailingZeros(s))
56+
ipNet := &net.IPNet{IP: s, Mask: net.CIDRMask(cidr, ipBits)}
57+
result = append(result, ipNet)
58+
tmp := lastIp(ipNet)
59+
if !lessThan(tmp, end) {
60+
return result
61+
}
62+
s = addOne(tmp)
63+
}
64+
}
65+
func (r *Range) ToRange() *Range {
66+
return r
67+
}
68+
func (r *Range) String() string {
69+
return ipToString(r.start) + "-" + ipToString(r.end)
70+
}
71+
72+
type IpWrapper struct {
73+
net.IP
74+
}
75+
76+
func (r IpWrapper) ToIp() net.IP {
77+
return r.IP
78+
}
79+
func (r IpWrapper) ToIpNets() []*net.IPNet {
80+
ipBits := len(r.IP) * 8
81+
return []*net.IPNet{
82+
{IP: r.IP, Mask: net.CIDRMask(ipBits, ipBits)},
83+
}
84+
}
85+
func (r IpWrapper) ToRange() *Range {
86+
return &Range{start: r.IP, end: r.IP}
87+
}
88+
func (r IpWrapper) String() string {
89+
return ipToString(r.IP)
90+
}
91+
92+
type IpNetWrapper struct {
93+
*net.IPNet
94+
}
95+
96+
func (r IpNetWrapper) ToIp() net.IP {
97+
if allFF(r.IPNet.Mask) {
98+
return r.IPNet.IP
99+
}
100+
return nil
101+
}
102+
func (r IpNetWrapper) ToIpNets() []*net.IPNet {
103+
return []*net.IPNet{r.IPNet}
104+
}
105+
func (r IpNetWrapper) ToRange() *Range {
106+
ipNet := r.IPNet
107+
return &Range{start: ipNet.IP, end: lastIp(ipNet)}
108+
}
109+
func (r IpNetWrapper) String() string {
110+
ip, mask := r.IP, r.Mask
111+
if ones, bitCount := mask.Size(); bitCount != 0 {
112+
return ipToString(ip) + "/" + strconv.Itoa(ones)
113+
}
114+
return ipToString(ip) + "/" + mask.String()
115+
}
116+
117+
func lessThan(a, b net.IP) bool {
118+
if lenA, lenB := len(a), len(b); lenA != lenB {
119+
return lenA < lenB
120+
}
121+
return bytes.Compare(a, b) < 0
122+
}
123+
124+
func max(a, b int) int {
125+
if a < b {
126+
return b
127+
}
128+
return a
129+
}
130+
131+
func allFF(ip []byte) bool {
132+
for _, c := range ip {
133+
if c != 0xff {
134+
return false
135+
}
136+
}
137+
return true
138+
}
139+
140+
func prefixLength(ip net.IP) int {
141+
for index, c := range ip {
142+
if c != 0 {
143+
return index*8 + bits.LeadingZeros8(c) + 1
144+
}
145+
}
146+
// special case for overflow
147+
return 0
148+
}
149+
150+
func trailingZeros(ip net.IP) int {
151+
ipLen := len(ip)
152+
for i := ipLen - 1; i >= 0; i-- {
153+
if c := ip[i]; c != 0 {
154+
return (ipLen-i-1)*8 + bits.TrailingZeros8(c)
155+
}
156+
}
157+
return ipLen * 8
158+
}
159+
160+
func lastIp(ipNet *net.IPNet) net.IP {
161+
ip, mask := ipNet.IP, ipNet.Mask
162+
ipLen := len(ip)
163+
assert(len(mask) == ipLen, "unexpected IPNet %v", ipNet)
164+
res := make(net.IP, ipLen)
165+
for i := 0; i < ipLen; i++ {
166+
res[i] = ip[i] | ^mask[i]
167+
}
168+
return res
169+
}
170+
171+
func addOne(ip net.IP) net.IP {
172+
ipLen := len(ip)
173+
res := make(net.IP, ipLen)
174+
for i := ipLen - 1; i >= 0; i-- {
175+
if t := ip[i]; t != 0xFF {
176+
res[i] = t + 1
177+
copy(res, ip[0:i])
178+
break
179+
}
180+
}
181+
return res
182+
}
183+
184+
func xor(a, b net.IP) net.IP {
185+
ipLen := len(a)
186+
assert(ipLen == len(b), "a=%v, b=%v", a, b)
187+
res := make(net.IP, ipLen)
188+
for i := ipLen - 1; i >= 0; i-- {
189+
res[i] = a[i] ^ b[i]
190+
}
191+
return res
192+
}
193+
194+
type Ranges []*Range
195+
196+
func (s Ranges) Len() int { return len(s) }
197+
func (s Ranges) Swap(i, j int) {
198+
s[i], s[j] = s[j], s[i]
199+
}
200+
func (s Ranges) Less(i, j int) bool {
201+
return lessThan(s[i].start, s[j].start)
202+
}
203+
204+
func sortAndMerge(wrappers []IRange) []IRange {
205+
if len(wrappers) < 2 {
206+
return wrappers
207+
}
208+
ranges := make([]*Range, 0, len(wrappers))
209+
for _, e := range wrappers {
210+
ranges = append(ranges, e.ToRange())
211+
}
212+
sort.Sort(Ranges(ranges))
213+
214+
res := make([]IRange, 0, len(ranges))
215+
now := ranges[0]
216+
familyLength := now.familyLength()
217+
start, end := now.start, now.end
218+
for i, count := 1, len(ranges); i < count; i++ {
219+
now := ranges[i]
220+
if fl := now.familyLength(); fl != familyLength {
221+
res = append(res, &Range{start, end})
222+
familyLength = fl
223+
start, end = now.start, now.end
224+
continue
225+
}
226+
if allFF(end) || !lessThan(addOne(end), now.start) {
227+
if lessThan(end, now.end) {
228+
end = now.end
229+
}
230+
} else {
231+
res = append(res, &Range{start, end})
232+
start, end = now.start, now.end
233+
}
234+
}
235+
return append(res, &Range{start, end})
236+
}

merge/main.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package main
2+
3+
// shamelessly copied from <https://github.com/zhanhb/cidr-merger>
4+
// thank you!
5+
6+
import (
7+
"bufio"
8+
"fmt"
9+
"net"
10+
"os"
11+
)
12+
13+
var privateCIDRs = []string{
14+
"0.0.0.0/8",
15+
"10.0.0.0/8",
16+
"100.64.0.0/10",
17+
"127.0.0.0/8",
18+
"169.254.0.0/16",
19+
"172.16.0.0/12",
20+
"192.0.0.0/24",
21+
"192.0.2.0/24",
22+
"192.88.99.0/24",
23+
"192.168.0.0/16",
24+
"198.18.0.0/15",
25+
"198.51.100.0/24",
26+
"203.0.113.0/24",
27+
"224.0.0.0/4",
28+
"240.0.0.0/4",
29+
"255.255.255.255/32",
30+
"::1/128",
31+
"fc00::/7",
32+
"fe80::/10",
33+
}
34+
35+
func parse(text string) (IRange, error) {
36+
if _, network, err := net.ParseCIDR(text); err == nil {
37+
// if network overlaps with private range
38+
for _, cidr := range privateCIDRs {
39+
if _, private, err := net.ParseCIDR(cidr); err == nil {
40+
if private.Contains(network.IP) {
41+
return nil, fmt.Errorf("[merge] %s overlaps within private range %s, ignoring", text, cidr)
42+
}
43+
}
44+
}
45+
return IpNetWrapper{network}, nil
46+
} else {
47+
return nil, err
48+
}
49+
}
50+
51+
func main() {
52+
var input = bufio.NewScanner(os.Stdin)
53+
54+
input.Split(bufio.ScanWords)
55+
var arr []IRange
56+
for input.Scan() {
57+
if text := input.Text(); text != "" {
58+
if maybe, err := parse(text); err != nil {
59+
fmt.Fprintln(os.Stderr, err)
60+
} else {
61+
arr = append(arr, maybe)
62+
}
63+
}
64+
if err := input.Err(); err != nil {
65+
panic(err)
66+
}
67+
}
68+
result := sortAndMerge(arr)
69+
70+
writer := bufio.NewWriter(os.Stdout)
71+
for _, r := range result {
72+
for _, cidr := range r.ToIpNets() {
73+
fmt.Fprintln(writer, IpNetWrapper{cidr})
74+
}
75+
}
76+
if err := writer.Flush(); err != nil {
77+
panic(err)
78+
}
79+
}

0 commit comments

Comments
 (0)