Compare commits

...

21 Commits

Author SHA1 Message Date
9ed5cea6e8 tuto3: update checks 2021-04-01 09:49:35 +02:00
e6a4ffc2ed tuto3: update unbound (it is a real host now) 2021-04-01 09:49:17 +02:00
8d8df75b6b tuto3: Use the entire /etc directory for mainrouter
This is to avoid Ansible complaining about Resource busy files
2021-04-01 09:47:32 +02:00
ff2a68332b tuto3: various fixies 2021-04-01 09:47:17 +02:00
f81dd3448c tuto3: fix raz-my-dd command 2021-04-01 09:46:41 +02:00
2bb1da63d6 New workstations schema 2021-04-01 09:46:41 +02:00
3e3a0e9e37 token-validator: Implement token collector 2021-03-25 14:38:20 +01:00
ae3b2e6f3b New package: minichecker 2021-03-25 14:37:55 +01:00
5d8bcd55ce Update on tuto3 subject 2021-03-25 14:37:55 +01:00
c20ed6630b Add go module requirements for token-validator 2021-03-23 12:57:17 +01:00
a4aadc401a Unbound is now also an accessible machine 2021-03-23 12:57:17 +01:00
c889cb4283 checker: add resolver ping test 2021-03-22 01:08:39 +01:00
2baa88a7aa tuto3: done 2021-03-22 01:07:46 +01:00
6b81aebc71 dashboard: add tests for TP3 2021-03-22 01:07:46 +01:00
12c74ebbb3 dashboard: update display only when all calculation done 2021-03-21 20:57:18 +01:00
5500712d60 Tuto3 almost ready for 2022 2021-03-21 20:41:41 +01:00
bb03770b55 Add missing entries 2021-03-21 20:40:02 +01:00
656e16083d maatma: redesign pong storage, to reduce CPU and IO consumption 2021-03-21 20:39:37 +01:00
e6d71ee7f5 pkg: add router-tuto3, openwrt based 2021-03-21 20:39:37 +01:00
31f871ba67 checker: fix GLUE search for external domains 2021-03-16 17:13:09 +01:00
c7a1812c9f checker: fix glue error report 2021-03-16 17:09:48 +01:00
32 changed files with 2298 additions and 187 deletions

View File

@ -54,6 +54,22 @@ pkg/debian-tuto2: pkg/debian-tuto2/sshd_config pkg/debian-tuto2/gai.conf pkg/deb
linuxkit pkg build -org nemunaire pkg/debian-tuto2/ linuxkit pkg build -org nemunaire pkg/debian-tuto2/
touch pkg/debian-tuto2 touch pkg/debian-tuto2
pkg/debian-tuto3: pkg/debian-tuto3/sshd_config pkg/debian-tuto3/build.yml pkg/debian-tuto3/issue pkg/debian-tuto3/Dockerfile
linuxkit pkg build -org nemunaire pkg/debian-tuto3/
touch pkg/debian-tuto3
pkg/router-tuto3: pkg/router-tuto3/build.yml pkg/router-tuto3/Dockerfile
linuxkit pkg build -org nemunaire pkg/router-tuto3/
touch pkg/router-tuto3
pkg/tinydeb: pkg/tinydeb/sshd_config pkg/tinydeb/gai.conf pkg/tinydeb/build.yml pkg/tinydeb/Dockerfile
linuxkit pkg build -org nemunaire pkg/tinydeb/
touch pkg/tinydeb
pkg/nsd: pkg/nsd/sshd_config pkg/nsd/build.yml pkg/nsd/init pkg/nsd/Dockerfile
linuxkit pkg build -org nemunaire pkg/tinydeb/
touch pkg/nsd
tuto2-kernel: tuto2.yml tuto2-kernel: tuto2.yml
linuxkit build -docker $< linuxkit build -docker $<
tuto2-initrd.img: tuto2.yml tuto2-initrd.img: tuto2.yml
@ -75,8 +91,6 @@ tuto2-srs.iso: tuto2.iso pkg/debian-tuto2/isolinux.cfg
sudo rm -rf $(TDIR) sudo rm -rf $(TDIR)
isohybrid $@ isohybrid $@
tuto2-srs.iso.gz: tuto2-srs.iso
gzip -9 < $< > $@
tuto3-kernel: tuto3.yml tuto3-kernel: tuto3.yml
linuxkit build -docker $< linuxkit build -docker $<
@ -85,8 +99,12 @@ tuto3-initrd.img: tuto3.yml
tuto3-cmdline: tuto3.yml tuto3-cmdline: tuto3.yml
linuxkit build -docker $< linuxkit build -docker $<
tuto3.iso: tuto3.yml tuto3.iso: tuto3.yml pkg/debian-tuto3 pkg/router-tuto3 pkg/tinydeb pkg/unbound pkg/nsd
linuxkit build -docker -format iso-bios $< linuxkit build -docker -format iso-bios $<
tuto3.iso.gz: tuto3.iso
%.gz: %
gzip -9 < $< > $@ gzip -9 < $< > $@
%.torrent: %
mktorrent -o $@ -a http://ankh.serekh.nemunai.re:6969/announce -p -v $<

View File

@ -22,7 +22,10 @@ const (
year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits. Taken from miekg/dns year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits. Taken from miekg/dns
) )
var verbose = false var (
verbose = false
domainsHostingMap = map[string]string{}
)
// ICMP // ICMP
@ -48,13 +51,82 @@ func check_ping(ip string, cb func(pkt *ping.Packet)) (err error) {
func get_GLUE(domain string) (aaaa net.IP, err error) { func get_GLUE(domain string) (aaaa net.IP, err error) {
client := dns.Client{Net: "tcp", Timeout: time.Second * 5} client := dns.Client{Net: "tcp", Timeout: time.Second * 5}
dnssrv := "[2a01:e0a:2b:2250::b]:53"
if strings.HasSuffix(domain, adlin.DelegatedDomainSuffix) {
dnssrv = "[2a01:e0a:2b:2250::b]:53"
} else if v, ok := domainsHostingMap[domain]; ok {
dnssrv = v
} else {
// Looking for root NS
m := new(dns.Msg)
m.SetQuestion(".", dns.TypeNS)
m.RecursionDesired = false
m.SetEdns0(4096, true)
var r *dns.Msg
r, _, err = client.Exchange(m, dnssrv)
if err != nil {
return
}
if r == nil {
return nil, errors.New("response is nil during initial recursion")
}
if r.Rcode != dns.RcodeSuccess {
return nil, errors.New("failed to get a valid answer during initial recursion")
}
for _, answer := range r.Answer {
if t, ok := answer.(*dns.NS); ok {
dnssrv = t.Ns + ":53"
}
}
// Do casual recursion
i := 0
recursion:
for i = 0; i < 10; i++ {
m := new(dns.Msg)
m.SetQuestion(domain, dns.TypeNS)
m.RecursionDesired = false
m.SetEdns0(4096, true)
var r *dns.Msg
r, _, err = client.Exchange(m, dnssrv)
if err != nil {
return
}
if r == nil {
return nil, errors.New("response is nil during recursion")
}
if r.Rcode != dns.RcodeSuccess {
return nil, errors.New("failed to get a valid answer during recursion")
}
for _, answer := range r.Ns {
if t, ok := answer.(*dns.NS); ok {
dnssrv = t.Ns + ":53"
if t.Header().Name == domain {
break recursion
}
}
}
}
if i >= 10 {
return nil, fmt.Errorf("too much name recursions")
} else {
domainsHostingMap[domain] = dnssrv
}
}
m := new(dns.Msg) m := new(dns.Msg)
m.SetQuestion(domain, dns.TypeNS) m.SetQuestion(domain, dns.TypeNS)
m.RecursionDesired = false m.RecursionDesired = false
m.SetEdns0(4096, true) m.SetEdns0(4096, true)
var r *dns.Msg var r *dns.Msg
r, _, err = client.Exchange(m, "[2a01:e0a:2b:2250::b]:53") r, _, err = client.Exchange(m, dnssrv)
if err != nil { if err != nil {
return return
} }
@ -450,6 +522,21 @@ func studentsChecker() {
return return
} }
// PingResolver
if tunnel_version == 3 {
tmp := strings.Split(stdIP, ":")
tmp[len(tmp)-1] = "2"
stdResolverIP := strings.Join(tmp, ":")
go check_ping(stdResolverIP, func(_ *ping.Packet) {
if verbose {
log.Printf("%s resolver PONG", std.Login)
}
if _, err := std.UnlockChallenge(CheckMap[tunnel_version][PingResolver], ""); err != nil {
log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error())
}
})
}
dnsIP := stdIP dnsIP := stdIP
var glueErr error var glueErr error
// Is GLUE defined? // Is GLUE defined?
@ -484,7 +571,7 @@ func studentsChecker() {
// Check HTTP with DNS // Check HTTP with DNS
if glueErr != nil { if glueErr != nil {
std.RegisterChallengeError(100*(tunnel_version-1)+4, fmt.Errorf("Unable to perform the test due to GLUE problem: %w", err)) std.RegisterChallengeError(100*(tunnel_version-1)+4, fmt.Errorf("Unable to perform the test due to GLUE problem: %w", glueErr))
} else if err := check_http(addr.String(), std.MyDelegatedDomain()); err == nil { } else if err := check_http(addr.String(), std.MyDelegatedDomain()); err == nil {
if verbose { if verbose {
log.Printf("%s just unlocked HTTP challenge\n", std.Login) log.Printf("%s just unlocked HTTP challenge\n", std.Login)
@ -501,7 +588,7 @@ func studentsChecker() {
// Check HTTPs with DNS // Check HTTPs with DNS
if glueErr != nil { if glueErr != nil {
std.RegisterChallengeError(100*(tunnel_version-1)+5, fmt.Errorf("Unable to perform the test due to GLUE problem: %w", err)) std.RegisterChallengeError(100*(tunnel_version-1)+5, fmt.Errorf("Unable to perform the test due to GLUE problem: %w", glueErr))
} else if err := check_https(std.MyDelegatedDomain(), addr.String()); err == nil { } else if err := check_https(std.MyDelegatedDomain(), addr.String()); err == nil {
if verbose { if verbose {
log.Printf("%s just unlocked HTTPS challenge\n", std.Login) log.Printf("%s just unlocked HTTPS challenge\n", std.Login)
@ -564,11 +651,11 @@ func studentsChecker() {
if verbose { if verbose {
log.Printf("%s just unlocked HTTP IP (without DNS) challenge\n", std.Login) log.Printf("%s just unlocked HTTP IP (without DNS) challenge\n", std.Login)
} }
if _, err := std.UnlockChallenge(100*(tunnel_version-1)+0, ""); err != nil { if _, err := std.UnlockChallenge(CheckMap[tunnel_version][HTTPonIP], ""); err != nil {
log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error())
} }
} else { } else {
std.RegisterChallengeError(100*(tunnel_version-1)+0, err) std.RegisterChallengeError(CheckMap[tunnel_version][HTTPonIP], err)
if verbose { if verbose {
log.Printf("%s and HTTP IP (without DNS): %s\n", std.Login, err) log.Printf("%s and HTTP IP (without DNS): %s\n", std.Login, err)
} }

47
checker/checks.go Normal file
View File

@ -0,0 +1,47 @@
package main
type AdlinTest int
const (
HTTPonIP AdlinTest = iota
HTTPonAssociatedDomain
HTTPSonAssociatedDomain
DNSDelegation
HTTPonDelegatedDomain
HTTPSonDelegatedDomain
Matrix
SNI
DNSSEC
PingResolver
DHCPonRH
DHCPonGuests
RHaccessNews
RHaccessNet
GuestNet
)
var CheckMap = map[int]map[AdlinTest]int{
2: map[AdlinTest]int{
HTTPonIP: 100,
HTTPonAssociatedDomain: 101,
HTTPSonAssociatedDomain: 102,
DNSDelegation: 103,
HTTPonDelegatedDomain: 104,
HTTPSonDelegatedDomain: 105,
Matrix: 106,
DNSSEC: 107,
},
3: map[AdlinTest]int{
PingResolver: 200,
HTTPonIP: 201,
DNSDelegation: 203,
HTTPonDelegatedDomain: 204,
HTTPSonDelegatedDomain: 205,
Matrix: 206,
DHCPonRH: 208,
DHCPonGuests: 211,
RHaccessNews: 209,
RHaccessNet: 210,
GuestNet: 212,
},
}

19
go.mod Normal file
View File

@ -0,0 +1,19 @@
module git.nemunai.re/lectures/adlin
go 1.16
require (
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/gdamore/tcell v1.4.0
github.com/go-sql-driver/mysql v1.5.0
github.com/jcmturner/gokrb5/v8 v8.4.2
github.com/julienschmidt/httprouter v1.3.0
github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc
github.com/miekg/dns v1.1.41
github.com/pquerna/cachecontrol v0.0.0-20201205024021-ac21108117ac // indirect
github.com/rivo/tview v0.0.0-20210312174852-ae9464cc3598
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
gopkg.in/ldap.v2 v2.5.1
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
)

440
go.sum Normal file
View File

@ -0,0 +1,440 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk=
github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell v1.4.0 h1:vUnHwJRvcPQa3tzi+0QI4U9JINXYJlOz9yiaiPQ2wMU=
github.com/gdamore/tcell v1.4.0/go.mod h1:vxEiSDZdW3L+Uhjii9c3375IlDmR05bzxY404ZVSMo0=
github.com/gdamore/tcell/v2 v2.2.0 h1:vSyEgKwraXPSOkvCk7IwOSyX+Pv3V2cV9CikJMXg4U4=
github.com/gdamore/tcell/v2 v2.2.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8=
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJzodkA=
github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc=
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc h1:m7rJJJeXrYCFpsxXYapkDW53wJCDmf9bsIXUg0HoeQY=
github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc/go.mod h1:eOj1DDj3NAZ6yv+WafaKzY37MFZ58TdfIhQ+8nQbiis=
github.com/mdlayher/ethernet v0.0.0-20190313224307-5b5fc417d966 h1:O3p5UmisBhl3V6lgs4Vdfg8HpjzbWJPyOfGLdwVJSmI=
github.com/mdlayher/ethernet v0.0.0-20190313224307-5b5fc417d966/go.mod h1:5s5p/sMJ6sNsFl6uCh85lkFGV8kLuIYJCRJLavVJwvg=
github.com/mdlayher/raw v0.0.0-20190313224157-43dbcdd7739d h1:rjAS0af7FIYCScTtEU5KjIldC6qVaEScUJhABHC+ccM=
github.com/mdlayher/raw v0.0.0-20190313224157-43dbcdd7739d/go.mod h1:r1fbeITl2xL/zLbVnNHFyOzQJTgr/3fpf1lJX/cjzR8=
github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/cachecontrol v0.0.0-20201205024021-ac21108117ac h1:jWKYCNlX4J5s8M0nHYkh7Y7c9gRVDEb3mq51j5J0F5M=
github.com/pquerna/cachecontrol v0.0.0-20201205024021-ac21108117ac/go.mod h1:hoLfEwdY11HjRfKFH6KqnPsfxlo3BP6bJehpDv8t6sQ=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rivo/tview v0.0.0-20210312174852-ae9464cc3598 h1:AbRrGXhagPRDItERv7nauBUUPi7Ma3IGIj9FqkQKW6k=
github.com/rivo/tview v0.0.0-20210312174852-ae9464cc3598/go.mod h1:VzCN9WX13RF88iH2CaGkmdHOlsy1ZZQcTmNwROqC+LI=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9 h1:umElSU9WZirRdgu2yFHY0ayQkEnKiOC1TtM3fWXFnoU=
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84 h1:duBc5zuJsmJXYOVVE/6PxejI+N3AaCqKjtsoLn1Je5Q=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ldap.v2 v2.5.1 h1:wiu0okdNfjlBzg6UWvd1Hn8Y+Ux17/u/4nlk4CQr6tU=
gopkg.in/ldap.v2 v2.5.1/go.mod h1:oI0cpe/D7HRtBQl8aTg+ZmzFUAvu4lsv3eLXMLGFxWk=
gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View File

@ -114,8 +114,10 @@ CREATE TABLE IF NOT EXISTS student_challenge_errors(
if _, err := db.Exec(` if _, err := db.Exec(`
CREATE TABLE IF NOT EXISTS student_pong( CREATE TABLE IF NOT EXISTS student_pong(
id_student INTEGER NOT NULL, id_student INTEGER NOT NULL,
time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, last TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
count INTEGER UNSIGNED DEFAULT 1,
state BOOLEAN NOT NULL DEFAULT 0, state BOOLEAN NOT NULL DEFAULT 0,
CONSTRAINT one_pong UNIQUE (id_student,state),
FOREIGN KEY(id_student) REFERENCES students(id_student) FOREIGN KEY(id_student) REFERENCES students(id_student)
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin;
`); err != nil { `); err != nil {

View File

@ -6,18 +6,19 @@ import (
type Pong struct { type Pong struct {
Date time.Time Date time.Time
Count uint
State bool State bool
} }
func (s *Student) LastPongs() (pongs []*Pong, err error) { func (s *Student) LastPongs() (pongs []*Pong, err error) {
if rows, errr := DBQuery("SELECT time, state FROM student_pong WHERE id_student = ? ORDER BY time DESC", s.Id); errr != nil { if rows, errr := DBQuery("SELECT last, count, state FROM student_pong WHERE id_student = ? ORDER BY last DESC", s.Id); errr != nil {
return nil, errr return nil, errr
} else { } else {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
p := &Pong{} p := &Pong{}
if err = rows.Scan(&p.Date, &p.State); err != nil { if err = rows.Scan(&p.Date, &p.Count, &p.State); err != nil {
return return
} }
pongs = append(pongs, p) pongs = append(pongs, p)
@ -31,6 +32,9 @@ func (s *Student) LastPongs() (pongs []*Pong, err error) {
} }
func (s *Student) OnPong(state bool) (err error) { func (s *Student) OnPong(state bool) (err error) {
_, err = DBExec("INSERT INTO student_pong (id_student, time, state) VALUES (?, ?, ?)", s.Id, time.Now(), state) _, err = DBExec("INSERT INTO student_pong (id_student, last, state) VALUES (?, ?, ?)", s.Id, time.Now(), state)
if err != nil {
_, err = DBExec("UPDATE student_pong SET last = CURRENT_TIMESTAMP, count = count + 1 WHERE id_student = ? AND state = ?", s.Id, state)
}
return return
} }

View File

@ -1,6 +1,7 @@
package adlin package adlin
import ( import (
"crypto/ed25519"
"crypto/rand" "crypto/rand"
"crypto/sha512" "crypto/sha512"
"encoding/base64" "encoding/base64"
@ -14,6 +15,18 @@ import (
const StdNetmask = 80 const StdNetmask = 80
var (
collector_secret ed25519.PrivateKey
)
func SetCollectorSecret(b []byte) {
collector_secret = ed25519.NewKeyFromSeed(b)
}
func GetCollectorPublic() ed25519.PublicKey {
return collector_secret.Public().(ed25519.PublicKey)
}
func StudentIP(idstd int64) net.IP { func StudentIP(idstd int64) net.IP {
return net.ParseIP(fmt.Sprintf("2a01:e0a:2b:2252:%x::", idstd)) return net.ParseIP(fmt.Sprintf("2a01:e0a:2b:2252:%x::", idstd))
} }
@ -36,6 +49,10 @@ type WGDump struct {
KeepAlive string KeepAlive string
} }
func (d *WGDump) GetPubKey() ([]byte, error) {
return base64.StdEncoding.DecodeString(d.PubKey)
}
var ( var (
wgDumpCache_data map[string]*WGDump = nil wgDumpCache_data map[string]*WGDump = nil
wgDumpCache_time time.Time wgDumpCache_time time.Time
@ -111,6 +128,14 @@ func (tt *TunnelToken) GetStudentIP() string {
} }
} }
func (tt *TunnelToken) GenKeySign() []byte {
stdprivkey := ed25519.NewKeyFromSeed(tt.token[:ed25519.SeedSize])
stdpublic := []byte(stdprivkey.Public().(ed25519.PublicKey))
return ed25519.Sign(collector_secret, stdpublic)
}
func TokenFromText(token string) []byte { func TokenFromText(token string) []byte {
sha := sha512.Sum512([]byte(token)) sha := sha512.Sum512([]byte(token))
return sha[:] return sha[:]
@ -200,6 +225,23 @@ func (student *Student) GetActivesTunnels() (ts []*TunnelToken, err error) {
} }
} }
func (student *Student) GetActivesTunnelsPubKey() (ts []ed25519.PublicKey, err error) {
var activeTuns []*TunnelToken
activeTuns, err = student.GetActivesTunnels()
if err != nil {
return
}
for _, tun := range activeTuns {
if tun.Dump != nil {
pk := ed25519.NewKeyFromSeed(tun.token[:ed25519.SeedSize])
ts = append(ts, pk.Public().(ed25519.PublicKey))
}
}
return
}
func (student *Student) GetTunnelToken(token []byte) (t *TunnelToken, err error) { func (student *Student) GetTunnelToken(token []byte) (t *TunnelToken, err error) {
t = new(TunnelToken) t = new(TunnelToken)
err = DBQueryRow("SELECT token, token_text, id_student, pubkey, time, suffixip, version FROM student_tunnel_tokens WHERE token = ? AND id_student = ? ORDER BY time DESC", token, student.Id).Scan(&t.token, &t.TokenText, &t.IdStudent, &t.PubKey, &t.Time, &t.SuffixIP, &t.Version) err = DBQueryRow("SELECT token, token_text, id_student, pubkey, time, suffixip, version FROM student_tunnel_tokens WHERE token = ? AND id_student = ? ORDER BY time DESC", token, student.Id).Scan(&t.token, &t.TokenText, &t.IdStudent, &t.PubKey, &t.Time, &t.SuffixIP, &t.Version)

View File

@ -0,0 +1,23 @@
FROM golang:alpine as gobuild
ENV GOOS linux
ENV GOARCH amd64
RUN apk add --no-cache git gcc
WORKDIR /go/src/minichecker
ADD cmd ./
RUN GO111MODULE=off go get -d -v
RUN GO111MODULE=off go build -v -tags netgo
FROM alpine
MAINTAINER Pierre-Olivier Mercier <nemunaire@nemunai.re>
COPY --from=gobuild /go/src/minichecker/minichecker /bin/minichecker
RUN mkdir /etc/wireguard && touch /etc/wireguard/.wireguard
ENTRYPOINT ["/bin/minichecker"]

View File

@ -0,0 +1,2 @@
image: minichecker
network: true

View File

@ -0,0 +1,12 @@
[Interface]
PrivateKey = AKZx4pYq2Do2j/OOFFJ6eA/O7DiAkr6aINJRHdMnkVU=
[Peer]
PublicKey = uSpqyYovvP4OG6wDxZ0Qkq45MfyK58PMUuPaLesY8FI=
Endpoint = 82.64.31.248:42912
AllowedIPs = ::/0
PersistentKeepalive = 5
# MyIPv6=2a01:e0a:2b:2252:1::2a/64
# MyNetwork=2a01:e0a:2b:2252:1::/80
# GWIPv6=2a01:e0a:2b:2252::1
# MyLogin=nemunaire
# KeySign=lcUxw+Gw+m9q21yvAL5BJJ9xpACTefeyR6qBsBFPyO9lqtrq/qqWAvf/gITtXdNmRne4FU72pw9pzL2J8SVeAw==

View File

@ -0,0 +1 @@
QMzkCN3PPg

View File

@ -0,0 +1,169 @@
package main
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
"strings"
"time"
"github.com/miekg/dns"
"github.com/sparrc/go-ping"
)
const (
DEFAULT_RESOLVER = "2a01:e0a:2b:2250::1"
)
var (
verbose = false
test_name = ""
)
// ICMP
func check_ping(ip string, cb func(pkt *ping.Packet)) (err error) {
var pinger *ping.Pinger
pinger, err = ping.NewPinger(ip)
if err != nil {
return
}
defer pinger.Stop()
pinger.Timeout = time.Second * 5
pinger.Count = 1
pinger.OnRecv = cb
pinger.SetPrivileged(true)
pinger.Run()
return
}
func check_dns(domain, ip string) (aaaa net.IP, err error) {
client := dns.Client{Timeout: time.Second * 5}
m := new(dns.Msg)
m.SetQuestion(domain, dns.TypeAAAA)
var r *dns.Msg
r, _, err = client.Exchange(m, fmt.Sprintf("[%s]:53", ip))
if err != nil {
return
}
if r == nil {
err = errors.New("response is nil")
return
}
if r.Rcode != dns.RcodeSuccess {
err = errors.New("failed to get a valid answer")
return
}
for _, answer := range r.Answer {
if t, ok := answer.(*dns.AAAA); ok {
aaaa = t.AAAA
}
}
return
}
// PORT 80
func check_http(ip, dn string) (err error) {
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
req, errr := http.NewRequest("GET", fmt.Sprintf("http://[%s]/", ip), nil)
if errr != nil {
return errr
}
if dn != "" {
req.Header.Add("Host", strings.TrimSuffix(dn, "."))
}
var resp *http.Response
resp, err = client.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
if dn != "" && resp.StatusCode >= 400 {
return fmt.Errorf("Bad status, got: %d (%s)", resp.StatusCode, resp.Status)
}
_, err = ioutil.ReadAll(resp.Body)
return
}
// PORT 443
func check_https(domain, ip string) (err error) {
var resp *http.Response
resp, err = http.Get(fmt.Sprintf("https://%s/", strings.TrimSuffix(domain, ".")))
if err != nil {
return
}
defer resp.Body.Close()
if resp.StatusCode >= 300 && resp.StatusCode < 400 {
loc := resp.Header.Get("Location")
if loc != "" && strings.HasSuffix(dns.Fqdn(loc), domain) {
if dns.Fqdn(loc) == domain {
return fmt.Errorf("Redirection loop %s redirect to %s", domain, loc)
} else if err = check_https(dns.Fqdn(loc), ip); err != nil {
return fmt.Errorf("Error after following redirection to %s: %w", loc, err)
} else {
return
}
}
}
if resp.StatusCode >= 300 {
return fmt.Errorf("Bad status, got: %d (%s)", resp.StatusCode, resp.Status)
}
_, err = ioutil.ReadAll(resp.Body)
return
}
func wksChecker() {
if collectorpubkey == nil {
var err error
if collectorpubkey, err = getCollectorPublicKey(); err != nil {
log.Println("Contact collector:", err)
return
}
}
data, err := encodeData(SendMeta{Login: Login}, map[string]*string{
test_name: nil,
})
if err != nil {
log.Println("Unable to encode message:", err)
return
}
err = sendData(data)
if err != nil {
log.Println("Unable to send message:", err)
return
}
v, _ := json.Marshal(data)
if verbose {
log.Printf("sent %s", v)
}
return
}

View File

@ -0,0 +1,83 @@
package main
import (
"bytes"
"crypto/ed25519"
"encoding/base64"
"encoding/json"
"io/ioutil"
"net/http"
"time"
)
var (
Login string
KeySign string
target string
)
func getCollectorPublicKey() (key []byte, err error) {
var resp *http.Response
resp, err = http.Get(target + "/api/collector_info")
if err != nil {
return
}
defer resp.Body.Close()
rd := base64.NewDecoder(base64.StdEncoding, json.NewDecoder(resp.Body).Buffered())
return ioutil.ReadAll(rd)
}
type SendMeta struct {
Time time.Time `json:"time"`
Login string `json:"login"`
Test string `json:"test,omitempty"`
}
type SendContent struct {
Meta []byte `json:"meta"`
Data []byte `json:"data"`
Sign []byte `json:"sign"`
Key []byte `json:"key"`
KeySign string `json:"keysign"`
}
func encodeData(meta SendMeta, v interface{}) (data SendContent, err error) {
if meta.Time.IsZero() {
meta.Time = time.Now()
}
var b []byte
b, err = json.Marshal(meta)
if err != nil {
return
}
data.Meta = []byte(base64.StdEncoding.EncodeToString(b))
b, err = json.Marshal(v)
if err != nil {
return
}
data.Data = []byte(base64.StdEncoding.EncodeToString(b))
data.Sign = ed25519.Sign(myprivkey, append(data.Meta, data.Data...))
data.Key = myprivkey.Public().(ed25519.PublicKey)
data.KeySign = KeySign
return
}
func sendData(data SendContent) (err error) {
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(data)
var resp *http.Response
resp, err = http.Post(target+"/remote", "application/json", b)
if err != nil {
return
}
resp.Body.Close()
return
}

View File

@ -0,0 +1 @@
module example.com/mod

152
pkg/minichecker/cmd/main.go Normal file
View File

@ -0,0 +1,152 @@
package main
import (
"bytes"
"crypto/ed25519"
"crypto/sha512"
"flag"
"io/ioutil"
"log"
"math/rand"
"os"
"os/signal"
"path"
"syscall"
"time"
"gopkg.in/fsnotify.v1"
)
var (
myprivkey ed25519.PrivateKey
collectorpubkey ed25519.PublicKey
)
func main() {
var tokenfile = flag.String("token-file", "/etc/wireguard/adlin.token", "Path to your token file")
var wgfile = flag.String("wg-file", "/etc/wireguard/adlin.conf", "Path to your wireguard configuration file")
var interval = flag.Duration("check-interval", 30*time.Second, "Interval between two checks")
flag.StringVar(&test_name, "test-name", "", "Name of the test to report")
flag.StringVar(&target, "target", "https://adlin.nemunai.re", "HTTP server to contact")
flag.BoolVar(&verbose, "verbose", verbose, "Enable verbose mode")
flag.Parse()
if test_name == "" {
test_name, _ = os.Hostname()
}
// First load token if it exists
if _, err := os.Stat(*tokenfile); !os.IsNotExist(err) {
if err := loadToken(*tokenfile); err != nil {
log.Fatal("ERROR: Unable to read token file:", err)
}
} else {
log.Fatal("Unable to find token file:", err)
}
// Load of configuration if it exists
if _, err := os.Stat(*wgfile); !os.IsNotExist(err) {
if err := loadSettings(*wgfile); err != nil {
log.Println("ERROR: Unable to read wg settings:", err)
}
}
// Register SIGHUP
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP)
go func() {
for range c {
log.Println("SIGHUP received, reloading settings...")
if err := loadSettings(*wgfile); err != nil {
log.Println("ERROR: Unable to read wg settings:", err)
}
}
}()
// Watch the configuration file
if watcher, err := fsnotify.NewWatcher(); err != nil {
log.Fatal(err)
} else {
if err := watcher.Add(path.Dir(*wgfile)); err != nil {
log.Fatal("Unable to watch: ", path.Dir(*wgfile), ": ", err)
}
go func() {
defer watcher.Close()
for {
select {
case ev := <-watcher.Events:
if path.Base(ev.Name) == *wgfile && ev.Op&(fsnotify.Write|fsnotify.Create) != 0 {
log.Println("Settings file changes, reloading it!")
if err := loadSettings(*wgfile); err != nil {
log.Println("ERROR: Unable to read wg settings:", err)
}
}
case err := <-watcher.Errors:
log.Println("watcher error:", err)
}
}
}()
}
// Prepare graceful shutdown
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
// Delay first check randomly
rand.Seed(time.Now().UnixNano())
n := rand.Intn(10)
time.Sleep(time.Duration(n) * time.Second)
ticker := time.NewTicker(*interval)
defer ticker.Stop()
// Launch checker
//wksChecker()
loop:
for {
select {
case <-interrupt:
break loop
case <-ticker.C:
wksChecker()
}
}
}
func loadToken(filename string) error {
if fd, err := os.Open(filename); err != nil {
return err
} else {
defer fd.Close()
if b, err := ioutil.ReadAll(fd); err != nil {
return err
} else {
seed := sha512.Sum512(bytes.TrimSpace(b))
myprivkey = ed25519.NewKeyFromSeed(seed[:ed25519.SeedSize])
}
return nil
}
}
func loadSettings(filename string) error {
if fd, err := os.Open(filename); err != nil {
return err
} else {
defer fd.Close()
if b, err := ioutil.ReadAll(fd); err != nil {
return err
} else if wgConf, err := FromWgQuick(string(b), "wg0"); err != nil {
return err
} else {
Login = wgConf.Interface.MyLogin
KeySign = wgConf.Interface.KeySign
}
return nil
}
}

409
pkg/minichecker/cmd/wg.go Normal file
View File

@ -0,0 +1,409 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (C) 2019-2021 WireGuard LLC. All Rights Reserved.
*
* From https://git.zx2c4.com/wireguard-windows/conf/
*/
package main
import (
"crypto/subtle"
"encoding/base64"
"encoding/hex"
"fmt"
"net"
"strconv"
"strings"
"time"
)
const KeyLength = 32
type IPCidr struct {
IP net.IP
Cidr uint8
}
type Endpoint struct {
Host string
Port uint16
}
type Key [KeyLength]byte
type HandshakeTime time.Duration
type Bytes uint64
type Config struct {
Name string
Interface Interface
Peers []Peer
}
type Interface struct {
PrivateKey Key
MyLogin string
KeySign string
Addresses []IPCidr
ListenPort uint16
MTU uint16
DNS []net.IP
DNSSearch []string
PreUp string
PostUp string
PreDown string
PostDown string
}
type Peer struct {
PublicKey Key
PresharedKey Key
AllowedIPs []IPCidr
Endpoint Endpoint
PersistentKeepalive uint16
RxBytes Bytes
TxBytes Bytes
LastHandshakeTime HandshakeTime
}
func (k *Key) IsZero() bool {
var zeros Key
return subtle.ConstantTimeCompare(zeros[:], k[:]) == 1
}
type ParseError struct {
why string
offender string
}
func (e *ParseError) Error() string {
return fmt.Sprintf("%s: %q", e.why, e.offender)
}
func parseIPCidr(s string) (ipcidr *IPCidr, err error) {
var addrStr, cidrStr string
var cidr int
i := strings.IndexByte(s, '/')
if i < 0 {
addrStr = s
} else {
addrStr, cidrStr = s[:i], s[i+1:]
}
err = &ParseError{fmt.Sprintf("Invalid IP address"), s}
addr := net.ParseIP(addrStr)
if addr == nil {
return
}
maybeV4 := addr.To4()
if maybeV4 != nil {
addr = maybeV4
}
if len(cidrStr) > 0 {
err = &ParseError{fmt.Sprintf("Invalid network prefix length"), s}
cidr, err = strconv.Atoi(cidrStr)
if err != nil || cidr < 0 || cidr > 128 {
return
}
if cidr > 32 && maybeV4 != nil {
return
}
} else {
if maybeV4 != nil {
cidr = 32
} else {
cidr = 128
}
}
return &IPCidr{addr, uint8(cidr)}, nil
}
func parseEndpoint(s string) (*Endpoint, error) {
i := strings.LastIndexByte(s, ':')
if i < 0 {
return nil, &ParseError{fmt.Sprintf("Missing port from endpoint"), s}
}
host, portStr := s[:i], s[i+1:]
if len(host) < 1 {
return nil, &ParseError{fmt.Sprintf("Invalid endpoint host"), host}
}
port, err := parsePort(portStr)
if err != nil {
return nil, err
}
hostColon := strings.IndexByte(host, ':')
if host[0] == '[' || host[len(host)-1] == ']' || hostColon > 0 {
err := &ParseError{fmt.Sprintf("Brackets must contain an IPv6 address"), host}
if len(host) > 3 && host[0] == '[' && host[len(host)-1] == ']' && hostColon > 0 {
end := len(host) - 1
if i := strings.LastIndexByte(host, '%'); i > 1 {
end = i
}
maybeV6 := net.ParseIP(host[1:end])
if maybeV6 == nil || len(maybeV6) != net.IPv6len {
return nil, err
}
} else {
return nil, err
}
host = host[1 : len(host)-1]
}
return &Endpoint{host, uint16(port)}, nil
}
func parseMTU(s string) (uint16, error) {
m, err := strconv.Atoi(s)
if err != nil {
return 0, err
}
if m < 576 || m > 65535 {
return 0, &ParseError{fmt.Sprintf("Invalid MTU"), s}
}
return uint16(m), nil
}
func parsePort(s string) (uint16, error) {
m, err := strconv.Atoi(s)
if err != nil {
return 0, err
}
if m < 0 || m > 65535 {
return 0, &ParseError{fmt.Sprintf("Invalid port"), s}
}
return uint16(m), nil
}
func parsePersistentKeepalive(s string) (uint16, error) {
if s == "off" {
return 0, nil
}
m, err := strconv.Atoi(s)
if err != nil {
return 0, err
}
if m < 0 || m > 65535 {
return 0, &ParseError{fmt.Sprintf("Invalid persistent keepalive"), s}
}
return uint16(m), nil
}
func parseKeyBase64(s string) (*Key, error) {
k, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return nil, &ParseError{fmt.Sprintf("Invalid key: %v", err), s}
}
if len(k) != KeyLength {
return nil, &ParseError{fmt.Sprintf("Keys must decode to exactly 32 bytes"), s}
}
var key Key
copy(key[:], k)
return &key, nil
}
func parseKeyHex(s string) (*Key, error) {
k, err := hex.DecodeString(s)
if err != nil {
return nil, &ParseError{fmt.Sprintf("Invalid key: %v", err), s}
}
if len(k) != KeyLength {
return nil, &ParseError{fmt.Sprintf("Keys must decode to exactly 32 bytes"), s}
}
var key Key
copy(key[:], k)
return &key, nil
}
func parseBytesOrStamp(s string) (uint64, error) {
b, err := strconv.ParseUint(s, 10, 64)
if err != nil {
return 0, &ParseError{fmt.Sprintf("Number must be a number between 0 and 2^64-1: %v", err), s}
}
return b, nil
}
func splitList(s string) ([]string, error) {
var out []string
for _, split := range strings.Split(s, ",") {
trim := strings.TrimSpace(split)
if len(trim) == 0 {
return nil, &ParseError{fmt.Sprintf("Two commas in a row"), s}
}
out = append(out, trim)
}
return out, nil
}
type parserState int
const (
inInterfaceSection parserState = iota
inPeerSection
notInASection
)
func (c *Config) maybeAddPeer(p *Peer) {
if p != nil {
c.Peers = append(c.Peers, *p)
}
}
func FromWgQuick(s string, name string) (*Config, error) {
lines := strings.Split(s, "\n")
parserState := notInASection
conf := Config{Name: name}
sawPrivateKey := false
var peer *Peer
for _, line := range lines {
pound := strings.IndexByte(line, '#')
if pound >= 0 {
if !strings.Contains(line, "MyLogin") && !strings.Contains(line, "KeySign") {
line = line[:pound]
} else {
line = line[pound+1:]
}
}
line = strings.TrimSpace(line)
lineLower := strings.ToLower(line)
if len(line) == 0 {
continue
}
if lineLower == "[interface]" {
conf.maybeAddPeer(peer)
parserState = inInterfaceSection
continue
}
if lineLower == "[peer]" {
conf.maybeAddPeer(peer)
peer = &Peer{}
parserState = inPeerSection
continue
}
if parserState == notInASection {
return nil, &ParseError{fmt.Sprintf("Line must occur in a section"), line}
}
equals := strings.IndexByte(line, '=')
if equals < 0 {
return nil, &ParseError{fmt.Sprintf("Config key is missing an equals separator"), line}
}
key, val := strings.TrimSpace(lineLower[:equals]), strings.TrimSpace(line[equals+1:])
if len(val) == 0 {
return nil, &ParseError{fmt.Sprintf("Key must have a value"), line}
}
if parserState == inInterfaceSection {
switch key {
case "privatekey":
k, err := parseKeyBase64(val)
if err != nil {
return nil, err
}
conf.Interface.PrivateKey = *k
sawPrivateKey = true
case "listenport":
p, err := parsePort(val)
if err != nil {
return nil, err
}
conf.Interface.ListenPort = p
case "mtu":
m, err := parseMTU(val)
if err != nil {
return nil, err
}
conf.Interface.MTU = m
case "address":
addresses, err := splitList(val)
if err != nil {
return nil, err
}
for _, address := range addresses {
a, err := parseIPCidr(address)
if err != nil {
return nil, err
}
conf.Interface.Addresses = append(conf.Interface.Addresses, *a)
}
case "dns":
addresses, err := splitList(val)
if err != nil {
return nil, err
}
for _, address := range addresses {
a := net.ParseIP(address)
if a == nil {
conf.Interface.DNSSearch = append(conf.Interface.DNSSearch, address)
} else {
conf.Interface.DNS = append(conf.Interface.DNS, a)
}
}
case "preup":
conf.Interface.PreUp = val
case "postup":
conf.Interface.PostUp = val
case "predown":
conf.Interface.PreDown = val
case "postdown":
conf.Interface.PostDown = val
default:
return nil, &ParseError{fmt.Sprintf("Invalid key for [Interface] section"), key}
}
} else if parserState == inPeerSection {
switch key {
case "publickey":
k, err := parseKeyBase64(val)
if err != nil {
return nil, err
}
peer.PublicKey = *k
case "presharedkey":
k, err := parseKeyBase64(val)
if err != nil {
return nil, err
}
peer.PresharedKey = *k
case "allowedips":
addresses, err := splitList(val)
if err != nil {
return nil, err
}
for _, address := range addresses {
a, err := parseIPCidr(address)
if err != nil {
return nil, err
}
peer.AllowedIPs = append(peer.AllowedIPs, *a)
}
case "persistentkeepalive":
p, err := parsePersistentKeepalive(val)
if err != nil {
return nil, err
}
peer.PersistentKeepalive = p
case "endpoint":
e, err := parseEndpoint(val)
if err != nil {
return nil, err
}
peer.Endpoint = *e
case "mylogin":
conf.Interface.MyLogin = val
case "keysign":
conf.Interface.KeySign = val
default:
return nil, &ParseError{fmt.Sprintf("Invalid key for [Peer] section"), key}
}
}
}
conf.maybeAddPeer(peer)
if !sawPrivateKey {
return nil, &ParseError{fmt.Sprintf("An interface must have a private key"), fmt.Sprintf("[none specified]")}
}
for _, p := range conf.Peers {
if p.PublicKey.IsZero() {
return nil, &ParseError{fmt.Sprintf("All peers must have public keys"), fmt.Sprintf("[none specified]")}
}
}
return &conf, nil
}

View File

@ -0,0 +1,14 @@
FROM openwrtorg/rootfs:x86-64-19.07.7
RUN mkdir -p /var/lock/ && opkg update && opkg install \
bind-dig \
curl \
ethtool \
luci-proto-wireguard \
nano \
ssmtp \
python \
tcpdump \
&& rm -rf /var/lock \
&& rm -rf /etc/ssh/ssh_host_*_key* \
&& echo "alias ip='ip -c'" >> /etc/profile

View File

@ -0,0 +1,2 @@
image: router-tuto3
network: true

View File

@ -1,15 +1,17 @@
FROM alpine FROM alpine
MAINTAINER Pierre-Olivier Mercier <nemunaire@nemunai.re> MAINTAINER Pierre-Olivier Mercier <nemunaire@nemunai.re>
RUN apk add --no-cache unbound dnssec-root RUN apk add --no-cache alpine-baselayout bash busybox unbound unbound-openrc dnssec-root openssh openrc
COPY docker-entrypoint.sh /
VOLUME /etc/unbound VOLUME /etc/unbound
EXPOSE 53 EXPOSE 53
EXPOSE 53/udp EXPOSE 53/udp
ENTRYPOINT ["/docker-entrypoint.sh"] RUN unbound-anchor && mkdir -p /var/log && touch /var/log/unbound.log && chown unbound:unbound /var/log/unbound.log
CMD ["/usr/sbin/unbound", "-d"] RUN rc-update add unbound default && rc-update add sshd default && rc-update add networking default
COPY sshd_config /etc/ssh/sshd_config
CMD ["/sbin/openrc-init"]
LABEL org.mobyproject.config='{"binds": ["/etc/resolv.conf:/etc/resolv.conf"], "capabilities": ["CAP_NET_BIND_SERVICE"]}' LABEL org.mobyproject.config='{"binds": ["/etc/resolv.conf:/etc/resolv.conf"], "capabilities": ["CAP_NET_BIND_SERVICE"]}'

104
pkg/unbound/sshd_config Normal file
View File

@ -0,0 +1,104 @@
# $OpenBSD: sshd_config,v 1.100 2016/08/15 12:32:04 naddy Exp $
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
#SyslogFacility AUTH
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
PermitRootLogin yes
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
#PubkeyAuthentication yes
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
#AuthorizedPrincipalsFile none
#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no
# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication no
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
UsePAM yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
#UsePrivilegeSeparation sandbox
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100

View File

@ -12,7 +12,7 @@ cmdline() {
[ -f "/var/lib/adlin/wireguard/adlin.token" ] && WGTOKEN=$(cat /var/lib/adlin/wireguard/adlin.token) [ -f "/var/lib/adlin/wireguard/adlin.token" ] && WGTOKEN=$(cat /var/lib/adlin/wireguard/adlin.token)
[ -z "${WGTOKEN}" ] && WGTOKEN=$(cmdline adlin.token) [ -z "${WGTOKEN}" ] && WGTOKEN=$(cmdline adlin.token)
[ -z "${WGTOKEN}" ] && { [ -z "${WGTOKEN}" ] && {
echo "You didn't define your token to connect the network. Please run here `join-p0m` and then reboot." echo "You didn't define your token to connect the network. Please run here \`join-maatma\` and then reboot."
exit 1 exit 1
} }
[ -f "/var/lib/adlin/wireguard/adlin.conf" ] && WGPRVKEY=$(sed 's/^.*PrivateKey *= *//p;d' /var/lib/adlin/wireguard/adlin.conf) [ -f "/var/lib/adlin/wireguard/adlin.conf" ] && WGPRVKEY=$(sed 's/^.*PrivateKey *= *//p;d' /var/lib/adlin/wireguard/adlin.conf)
@ -23,9 +23,9 @@ do
exit 1 exit 1
done done
echo -n "${WGTOKEN}" > /var/lib/adlin/wireguard/adlin.token echo -n "${WGTOKEN}" > /var/lib/adlin/wireguard/adlin.token
/sbin/ip link add dev wg0 type wireguard #/sbin/ip link add dev wg0 type wireguard
/usr/bin/wg setconf wg0 /var/lib/adlin/wireguard/adlin.conf #/usr/bin/wg setconf wg0 /var/lib/adlin/wireguard/adlin.conf
/sbin/ip address add dev wg0 $(sed 's/^.*MyIPv6=//p;d' /var/lib/adlin/wireguard/adlin.conf) #/sbin/ip address add dev wg0 $(sed 's/^.*MyIPv6=//p;d' /var/lib/adlin/wireguard/adlin.conf)
/sbin/ip link set up dev wg0 #/sbin/ip link set up dev wg0
/sbin/ip -6 route del default #/sbin/ip -6 route del default
/sbin/ip -6 route add default via $(sed 's/^.*GWIPv6=//p;d' /var/lib/adlin/wireguard/adlin.conf) pref high #/sbin/ip -6 route add default via $(sed 's/^.*GWIPv6=//p;d' /var/lib/adlin/wireguard/adlin.conf) pref high

View File

@ -23,6 +23,14 @@ var tuto_progress = [
107: { title: "DNSSEC (bonus)", icon: "7", label: "DNSSEC"}, 107: { title: "DNSSEC (bonus)", icon: "7", label: "DNSSEC"},
}, },
{ {
200: { title: "HTTP", label: "HTTP"}, 200: { title: "PONG resolver", icon: "0", label: "PONG srv"},
201: { title: "HTTP on IP (bonus)", icon: "1", label: "HTTP IP"},
203: { title: "DNS Delegation", icon: "2", label: "DNS"},
204: { title: "HTTP on delegated domain", icon: "3", label: "HTTP on NS"},
205: { title: "HTTPS on delegated domain", icon: "4", label: "HTTPS on NS"},
206: { title: "Matrix", icon: "5", label: "Matrix"},
208: { title: "RH access net", icon: "6", label: "RH net"},
209: { title: "DG access net", icon: "7", label: "DG net"},
210: { title: "CM access net", icon: "8", label: "CM net"},
}, },
]; ];

View File

@ -109,22 +109,26 @@ angular.module("AdLinApp")
.controller("StudentProgressionController", function($scope, $interval, $http, Student, StudentProgression) { .controller("StudentProgressionController", function($scope, $interval, $http, Student, StudentProgression) {
$scope.tuto_progress = tuto_progress; $scope.tuto_progress = tuto_progress;
var refreshStd = function() { var refreshStd = function() {
$scope.student = Student.get({studentId: $scope.onestudent}) var student = Student.get({studentId: $scope.onestudent})
$scope.img = $scope.onestudent == "nemunaire" ? "mercie_d" : $scope.onestudent student.$promise.then(function(stdnt) {
$scope.mychallenges = StudentProgression.get({studentId: $scope.onestudent}) $scope.student = stdnt
$scope.mychallenges.$promise.then(function(mychallenges) {
angular.forEach(mychallenges, function(ch, chid) {
if (ch.time) {
mychallenges[chid].time = new Date(ch.time);
mychallenges[chid].recent = (Date.now() - mychallenges[chid].time)/1000;
}
});
})
$scope.student.$promise.then(function(student) {
$http.get("/api/students/" + $scope.student.id + "/ips").then(function(response) { $http.get("/api/students/" + $scope.student.id + "/ips").then(function(response) {
$scope.ips = response.data; $scope.ips = response.data;
}); });
}) })
var mychallenges = StudentProgression.get({studentId: $scope.onestudent})
mychallenges.$promise.then(function(mychals) {
angular.forEach(mychals, function(ch, chid) {
if (ch.time) {
mychals[chid].time = new Date(ch.time);
mychals[chid].recent = (Date.now() - mychals[chid].time)/1000;
}
});
$scope.mychallenges = mychals
})
$scope.img = $scope.onestudent == "nemunaire" ? "mercie_d" : $scope.onestudent
} }
$scope.$watch("onestudent", function(onestudent) { $scope.$watch("onestudent", function(onestudent) {
refreshStd(); refreshStd();

View File

@ -2,6 +2,7 @@ package main
import ( import (
"context" "context"
"encoding/base64"
"flag" "flag"
"fmt" "fmt"
"log" "log"
@ -16,7 +17,9 @@ import (
"git.nemunai.re/lectures/adlin/libadlin" "git.nemunai.re/lectures/adlin/libadlin"
) )
var baseURL string = "/" var (
baseURL string = "/"
)
type ResponseWriterPrefix struct { type ResponseWriterPrefix struct {
real http.ResponseWriter real http.ResponseWriter
@ -59,6 +62,8 @@ func StripPrefix(prefix string, h http.Handler) http.Handler {
} }
func main() { func main() {
var err error
if v, exists := os.LookupEnv("ADLIN_NS_HOST"); exists { if v, exists := os.LookupEnv("ADLIN_NS_HOST"); exists {
ControlSocket = v ControlSocket = v
} }
@ -68,6 +73,13 @@ func main() {
if v, exists := os.LookupEnv("ADLIN_TSIG_SECRET"); exists { if v, exists := os.LookupEnv("ADLIN_TSIG_SECRET"); exists {
tsigSecret = v tsigSecret = v
} }
if v, exists := os.LookupEnv("ADLIN_COLLECTOR_SECRET"); !exists {
log.Fatal("Please define ADLIN_COLLECTOR_SECRET environment variable")
} else if t, err := base64.StdEncoding.DecodeString(v); err != nil {
log.Fatal("Error reading ADLIN_COLLECTOR_SECRET variable:", err)
} else {
adlin.SetCollectorSecret(t)
}
var bind = flag.String("bind", ":8081", "Bind port/socket") var bind = flag.String("bind", ":8081", "Bind port/socket")
var dsn = flag.String("dsn", adlin.DSNGenerator(), "DSN to connect to the MySQL server") var dsn = flag.String("dsn", adlin.DSNGenerator(), "DSN to connect to the MySQL server")
@ -82,7 +94,6 @@ func main() {
flag.Parse() flag.Parse()
// Sanitize options // Sanitize options
var err error
log.Println("Checking paths...") log.Println("Checking paths...")
if err = sanitizeStaticOptions(); err != nil { if err = sanitizeStaticOptions(); err != nil {
log.Fatal(err) log.Fatal(err)

View File

@ -17,6 +17,9 @@ import (
) )
func init() { func init() {
router.GET("/api/collector_info", apiHandler(func(ps httprouter.Params, body []byte) (interface{}, error) {
return "\"" + base64.StdEncoding.EncodeToString(adlin.GetCollectorPublic()) + "\"", nil
}))
router.GET("/api/wg.conf", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { router.GET("/api/wg.conf", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
w.Header().Set("Content-Type", "text/plain") w.Header().Set("Content-Type", "text/plain")
@ -149,7 +152,8 @@ PersistentKeepalive = 5
# MyNetwork=%s/%d # MyNetwork=%s/%d
# GWIPv6=%s # GWIPv6=%s
# MyLogin=%s # MyLogin=%s
`, base64.StdEncoding.EncodeToString(tinfo.SrvPubKey), "82.64.31.248", tinfo.SrvPort, tinfo.CltIPv6, token.SuffixIP, 64, tinfo.CltIPv6, tinfo.CltRange, tinfo.SrvGW6, student.Login))) # KeySign=%s
`, base64.StdEncoding.EncodeToString(tinfo.SrvPubKey), "82.64.31.248", tinfo.SrvPort, tinfo.CltIPv6, token.SuffixIP, 64, tinfo.CltIPv6, tinfo.CltRange, tinfo.SrvGW6, student.Login, base64.StdEncoding.EncodeToString(token.GenKeySign()))))
} }
func updateWgTunnel(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { func updateWgTunnel(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {

537
tuto3.yml
View File

@ -1,5 +1,5 @@
kernel: kernel:
image: linuxkit/kernel:4.19.113 image: linuxkit/kernel:4.19.121
# cmdline: "console=ttyS0 root=/dev/sda1 root=/dev/sr0 adlin.token=LqCdJDfniA" # cmdline: "console=ttyS0 root=/dev/sda1 root=/dev/sr0 adlin.token=LqCdJDfniA"
cmdline: "console=tty0" cmdline: "console=tty0"
@ -40,9 +40,25 @@ onboot:
net: /run/netns/router net: /run/netns/router
services: services:
- name: dhcpcd-wks1 - name: dhcpcd-wks-dg1
image: linuxkit/dhcpcd:v0.8 image: linuxkit/dhcpcd:v0.8
hostname: wks1 hostname: wks-dg1
net: new
pid: new
ipc: new
uts: new
runtime:
interfaces:
- name: ethwks-dg1
bindNS:
net: /run/netns/wks-dg1
uts: /run/utsns/wks-dg1
binds:
- /var/lib/adlin/wks-dg1resolv.conf:/etc/resolv.conf
- name: dhcpcd-wks-rh1
image: linuxkit/dhcpcd:v0.8
hostname: wks-rh1
net: new net: new
pid: new pid: new
ipc: new ipc: new
@ -50,55 +66,72 @@ services:
runtime: runtime:
interfaces: interfaces:
- name: eth1 - name: eth1
- name: ethwks1 - name: ethwks-rh1
bindNS: bindNS:
net: /run/netns/wks1 net: /run/netns/wks-rh1
uts: /run/utsns/wks1 uts: /run/utsns/wks-rh1
binds: binds:
- /var/lib/adlin/wks1resolv.conf:/etc/resolv.conf - /var/lib/adlin/wks-rh1resolv.conf:/etc/resolv.conf
- name: dhcpcd-wks2 - name: dhcpcd-wks-rh2
image: linuxkit/dhcpcd:v0.8 image: linuxkit/dhcpcd:v0.8
hostname: wks2 hostname: wks-rh2
net: new net: new
pid: new pid: new
ipc: new ipc: new
uts: new uts: new
runtime: runtime:
interfaces: interfaces:
- name: ethwks2 - name: ethwks-rh2
bindNS: bindNS:
net: /run/netns/wks2 net: /run/netns/wks-rh2
uts: /run/utsns/wks2 uts: /run/utsns/wks-rh2
binds: binds:
- /var/lib/adlin/wks2resolv.conf:/etc/resolv.conf - /var/lib/adlin/wks-rh2resolv.conf:/etc/resolv.conf
- name: sshd-wks1 - name: dhcpcd-wks-cm1
image: linuxkit/dhcpcd:v0.8
hostname: wks-cm1
net: new
pid: new
ipc: new
uts: new
runtime:
interfaces:
- name: ethwks-cm1
bindNS:
net: /run/netns/wks-cm1
uts: /run/utsns/wks-cm1
binds:
- /var/lib/adlin/wks-cm1resolv.conf:/etc/resolv.conf
- name: sshd-wks-dg1
image: linuxkit/sshd:v0.8 image: linuxkit/sshd:v0.8
net: /run/netns/wks1 net: /run/netns/wks-dg1
uts: /run/utsns/wks1 uts: /run/utsns/wks-dg1
pid: new pid: new
ipc: new ipc: new
binds: binds:
- /etc/ssh/sshd_config:/etc/ssh/sshd_config - /etc/ssh/sshd_config:/etc/ssh/sshd_config
- /etc/wpasswd:/etc/passwd - /etc/wpasswd:/etc/passwd
- /etc/wshadow:/etc/shadow - /etc/wshadow:/etc/shadow
- /var/lib/adlin/wks1resolv.conf:/etc/resolv.conf - /var/lib/adlin/wks-dg1resolv.conf:/etc/resolv.conf
- name: sshd-wks2 - name: sshd-wks-rh1
image: linuxkit/sshd:v0.8 image: linuxkit/sshd:v0.8
net: /run/netns/wks2 net: /run/netns/wks-rh1
uts: /run/utsns/wks2 uts: /run/utsns/wks-rh1
pid: new pid: new
ipc: new ipc: new
binds: binds:
- /etc/ssh/sshd_config:/etc/ssh/sshd_config - /etc/ssh/sshd_config:/etc/ssh/sshd_config
- /etc/wpasswd:/etc/passwd - /etc/wpasswd:/etc/passwd
- /etc/wshadow:/etc/shadow - /etc/wshadow:/etc/shadow
- /var/lib/adlin/wks2resolv.conf:/etc/resolv.conf - /var/lib/adlin/wks-rh1resolv.conf:/etc/resolv.conf
- name: mainrouter - name: mainrouter
image: nemunaire/adlin-tuto3:a8593e91cb830dede2ad25a205ef47141a5a3c22 #image: nemunaire/adlin-tuto3:485bb9556ca3bc33e7fee16edd93c05f35eb1455
image: nemunaire/router-tuto3:c07718ca23c03ff5033c4042f0cbeca6c26d4e6f
net: /run/netns/router net: /run/netns/router
pid: new pid: new
ipc: new ipc: new
@ -111,10 +144,16 @@ services:
- type: cgroup - type: cgroup
options: ["rw","nosuid","noexec","nodev","relatime"] options: ["rw","nosuid","noexec","nodev","relatime"]
binds: binds:
- /var/lib/adlin/wrt-etc:/etc
- /etc/rinittab:/etc/inittab
- /etc/hosts:/etc/hosts:ro - /etc/hosts:/etc/hosts:ro
- /etc/dresolv.conf:/etc/resolv.conf - /etc/dresolv.conf:/etc/resolv.conf
- /etc/rsysctl.conf:/etc/sysctl.d/10-default.conf:ro
- /lib/preinit/20_check_iso:/lib/preinit/20_check_iso
- /lib/preinit/30_failsafe_wait:/lib/preinit/30_failsafe_wait
- /lib/preinit/99_10_failsafe_login:/lib/preinit/99_10_failsafe_login
- name: matrix - name: matrix
image: nemunaire/tinydeb:eaa617bf726fb4cadfa22b3947709579e6001212 image: nemunaire/tinydeb:2ec3c0260da7242df267799dfe08fe2eb0d014b1
net: /run/netns/chat net: /run/netns/chat
pid: new pid: new
ipc: new ipc: new
@ -130,7 +169,7 @@ services:
- /etc/hosts:/etc/hosts:ro - /etc/hosts:/etc/hosts:ro
- /etc/dresolv.conf:/etc/resolv.conf - /etc/dresolv.conf:/etc/resolv.conf
- name: ns-resolv - name: ns-resolv
image: nemunaire/unbound:ed3ccbb5340aefd48c53a97743fdc6edc7011103 image: nemunaire/unbound:4988e30d81f3b1782e7bc520d2d24123930d72a6
net: /run/netns/ns net: /run/netns/ns
pid: new pid: new
ipc: new ipc: new
@ -138,7 +177,11 @@ services:
hostname: resolvsrv hostname: resolvsrv
capabilities: capabilities:
- all - all
mounts:
- type: cgroup
options: ["rw","nosuid","noexec","nodev","relatime"]
binds: binds:
- /etc/network:/etc/network:ro
- /etc/unbound:/etc/unbound:ro - /etc/unbound:/etc/unbound:ro
- /etc/services:/etc/services:ro - /etc/services:/etc/services:ro
- name: ns-auth - name: ns-auth
@ -177,7 +220,7 @@ services:
- LANG=en_US.utf8 - LANG=en_US.utf8
- PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/" - PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/"
- PGDATA=/var/lib/postgresql/data - PGDATA=/var/lib/postgresql/data
- POSTGRES_PASSWORD=adlin2021 - POSTGRES_PASSWORD=adlin2022
binds: binds:
- /etc/services:/etc/services:ro - /etc/services:/etc/services:ro
- /initdb/:/docker-entrypoint-initdb.d/:ro - /initdb/:/docker-entrypoint-initdb.d/:ro
@ -194,7 +237,7 @@ services:
# env: # env:
# - MM_USERNAME=mattermost # - MM_USERNAME=mattermost
# - MM_DBNAME=mattermost # - MM_DBNAME=mattermost
# - MM_PASSWORD=adlin2021 # - MM_PASSWORD=adlin2022
# binds: # binds:
# - /etc/services:/etc/services:ro # - /etc/services:/etc/services:ro
# - /etc/hosts:/etc/hosts:ro # - /etc/hosts:/etc/hosts:ro
@ -209,18 +252,18 @@ services:
- all - all
command: ["/bin/sh", "-c", "sleep 10; /usr/bin/miniflux"] command: ["/bin/sh", "-c", "sleep 10; /usr/bin/miniflux"]
env: env:
- DATABASE_URL=postgres://miniflux:adlin2021@db/miniflux?sslmode=disable - DATABASE_URL=postgres://miniflux:adlin2022@db/miniflux?sslmode=disable
- RUN_MIGRATIONS=1 - RUN_MIGRATIONS=1
- CREATE_ADMIN=1 - CREATE_ADMIN=1
- ADMIN_USERNAME=adeline - ADMIN_USERNAME=adeline
- ADMIN_PASSWORD=adlin2021 - ADMIN_PASSWORD=adlin2022
- LISTEN_ADDR=0.0.0.0:8080 - LISTEN_ADDR=0.0.0.0:8080
binds: binds:
- /etc/hosts:/etc/hosts:ro - /etc/hosts:/etc/hosts:ro
- /etc/dresolv.conf:/etc/resolv.conf - /etc/dresolv.conf:/etc/resolv.conf
- /etc/services:/etc/services:ro - /etc/services:/etc/services:ro
- name: web - name: web
image: nemunaire/tinydeb:eaa617bf726fb4cadfa22b3947709579e6001212 image: nemunaire/tinydeb:2ec3c0260da7242df267799dfe08fe2eb0d014b1
net: /run/netns/web net: /run/netns/web
pid: new pid: new
ipc: new ipc: new
@ -235,17 +278,64 @@ services:
binds: binds:
- /etc/dresolv.conf:/etc/resolv.conf - /etc/dresolv.conf:/etc/resolv.conf
# Workstation testers
- name: minichecker-wks-rh2
image: nemunaire/minichecker:a5d37bb2ebed6df0e586184582763eb0cf727b51
net: /run/netns/wks-rh2
pid: new
ipc: new
uts: /run/utsns/wks-rh2
command: ["/bin/minichecker", "-check-interval", "50s", "-target", "https://adlin.nemunai.re"]
binds:
- /var/lib/adlin/wks-rh2resolv.conf:/etc/resolv.conf
- /var/lib/adlin/wireguard/:/etc/wireguard/:ro
- name: minichecker-wks-dg1
image: nemunaire/minichecker:a5d37bb2ebed6df0e586184582763eb0cf727b51
net: /run/netns/wks-dg1
pid: new
ipc: new
uts: /run/utsns/wks-dg1
command: ["/bin/minichecker", "-check-interval", "50s", "-target", "https://adlin.nemunai.re"]
binds:
- /etc/hosts-minichecker:/etc/hosts:ro
- /var/lib/adlin/wks-dg1resolv.conf:/etc/resolv.conf
- /var/lib/adlin/wireguard/:/etc/wireguard/:ro
- name: minichecker-wks-cm1
image: nemunaire/minichecker:a5d37bb2ebed6df0e586184582763eb0cf727b51
net: /run/netns/wks-cm1
pid: new
ipc: new
uts: /run/utsns/wks-cm1
command: ["/bin/minichecker", "-check-interval", "50s", "-target", "https://adlin.nemunai.re"]
binds:
- /etc/hosts-minichecker:/etc/hosts:ro
- /var/lib/adlin/wireguard/:/etc/wireguard/:ro
files: files:
- path: etc/hosts - path: etc/hosts
contents: | contents: |
127.0.0.1 localhost 127.0.0.1 localhost
::1 localhost ::1 localhost
172.23.42.2 ns 172.23.42.2 ns
172.23.42.3 ns-auth 172.23.42.3 ns-auth
172.23.42.4 db 172.23.42.4 db
172.23.42.5 matrix 172.23.42.5 matrix
172.23.42.6 news 172.23.42.6 news
172.23.42.7 web 172.23.42.7 web
82.64.31.248 adlin.nemunai.re
mode: "0444"
- path: etc/hosts-minichecker
contents: |
127.0.0.1 localhost
::1 localhost
172.23.42.2 ns
172.23.42.3 ns-auth
172.23.42.4 db
172.23.42.5 matrix
172.23.42.6 news
172.23.42.7 web
82.64.31.248 adlin.nemunai.re
mode: "0444" mode: "0444"
- path: etc/sysctl.d/adlin.conf - path: etc/sysctl.d/adlin.conf
@ -268,17 +358,17 @@ files:
- path: /usr/bin/reset-router-firewall - path: /usr/bin/reset-router-firewall
contents: | contents: |
#!/bin/sh #!/bin/sh
PS=$(pgrep systemd | head -1) PS=$(pgrep procd | head -1)
nsenter -t "${PS}" -a iptables -F nsenter -t "${PS}" -a -- iptables -F
nsenter -t "${PS}" -a iptables -P INPUT ACCEPT nsenter -t "${PS}" -a -- iptables -P INPUT ACCEPT
nsenter -t "${PS}" -a iptables -P FORWARD ACCEPT nsenter -t "${PS}" -a -- iptables -P FORWARD ACCEPT
nsenter -t "${PS}" -a iptables -P OUTPUT ACCEPT nsenter -t "${PS}" -a -- iptables -P OUTPUT ACCEPT
nsenter -t "${PS}" -a iptables -t nat -F nsenter -t "${PS}" -a -- iptables -t nat -F
mode: "0755" mode: "0755"
- path: /usr/sbin/wg - path: /usr/sbin/wg
contents: | contents: |
nsenter -n/run/netns/router /usr/bin/wg $@ nsenter -n/run/netns/router -- /usr/bin/wg $@
mode: "0755" mode: "0755"
- path: /initdb/init-miniflux.sh - path: /initdb/init-miniflux.sh
@ -286,7 +376,7 @@ files:
#!/bin/sh #!/bin/sh
set -e set -e
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
CREATE USER miniflux WITH PASSWORD 'adlin2021'; CREATE USER miniflux WITH PASSWORD 'adlin2022';
CREATE DATABASE miniflux; CREATE DATABASE miniflux;
GRANT ALL PRIVILEGES ON DATABASE miniflux TO miniflux; GRANT ALL PRIVILEGES ON DATABASE miniflux TO miniflux;
EOSQL EOSQL
@ -297,14 +387,14 @@ files:
- path: /initdb/init-matrix.sql - path: /initdb/init-matrix.sql
contents: | contents: |
CREATE USER matrix WITH PASSWORD 'adlin2021'; CREATE USER matrix WITH PASSWORD 'adlin2022';
CREATE DATABASE matrix ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' TEMPLATE template0 OWNER matrix; CREATE DATABASE matrix ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' TEMPLATE template0 OWNER matrix;
GRANT ALL PRIVILEGES ON DATABASE matrix TO matrix; GRANT ALL PRIVILEGES ON DATABASE matrix TO matrix;
mode: "0444" mode: "0444"
- path: /initdb/init-website.sql - path: /initdb/init-website.sql
contents: | contents: |
CREATE USER website WITH PASSWORD 'adlin2021'; CREATE USER website WITH PASSWORD 'adlin2022';
CREATE DATABASE website ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' TEMPLATE template0 OWNER website; CREATE DATABASE website ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' TEMPLATE template0 OWNER website;
GRANT ALL PRIVILEGES ON DATABASE website TO website; GRANT ALL PRIVILEGES ON DATABASE website TO website;
mode: "0444" mode: "0444"
@ -313,31 +403,31 @@ files:
contents: | contents: |
#!/bin/sh #!/bin/sh
mkdir -p /var/lib/adlin/ mkdir -p /var/lib/adlin/
rm -rf /var/lib/adlin/wks1resolv.conf /var/lib/adlin/wks2resolv.conf rm -rf /var/lib/adlin/wks-dg1resolv.conf /var/lib/adlin/wks-rh1resolv.conf /var/lib/adlin/wks-rh2resolv.conf /var/lib/adlin/wks-cm1resolv.conf
touch /var/lib/adlin/wks1resolv.conf /var/lib/adlin/wks2resolv.conf touch /var/lib/adlin/wks-dg1resolv.conf /var/lib/adlin/wks-rh1resolv.conf /var/lib/adlin/wks-rh2resolv.conf /var/lib/adlin/wks-cm1resolv.conf
mode: "0755" mode: "0755"
- path: etc/init.d/011-tuto-net - path: etc/init.d/011-tuto-net
contents: | contents: |
#!/bin/sh #!/bin/sh
mkdir -p /var/lib/adlin/wireguard/ mkdir -p /var/lib/adlin/wireguard/
nsenter -n/run/netns/router /usr/bin/ask.sh nsenter -n/run/netns/router -- /usr/bin/ask.sh
# Network: workstations # Network: workstations
ip link add ethwks type veth peer name veth-wks ip link add ethwks type veth peer name veth-wks
ip link set ethwks up
ip link set ethwks netns router ip link set ethwks netns router
ip netns exec router ip a add 192.168.6.254/24 dev ethwks #ip link set ethwks up
grep MyIPv6= /var/lib/adlin/wireguard/adlin.conf > /dev/null && #ip netns exec router ip a add 192.168.6.254/24 dev ethwks
ip netns exec router ip a add $(sed 's/^.*MyIPv6=//p;d' /var/lib/adlin/wireguard/adlin.conf | sed "s#:[^:/]*/.*\$#1::1/96#") dev ethwks #grep MyIPv6= /var/lib/adlin/wireguard/adlin.conf > /dev/null &&
# ip netns exec router ip a add $(sed 's/^.*MyIPv6=//p;d' /var/lib/adlin/wireguard/adlin.conf | sed "s#:[^:/]*/.*\$#1::1/96#") dev ethwks
# Network: servers # Network: servers
ip link add ethsrv type veth peer name veth-srv ip link add ethsrv type veth peer name veth-srv
ip link set ethsrv netns router ip link set ethsrv netns router
ip netns exec router ip link set ethsrv up #ip netns exec router ip link set ethsrv up
ip netns exec router ip a add 172.23.42.1/24 dev ethsrv #ip netns exec router ip a add 172.23.42.1/24 dev ethsrv
grep MyIPv6= /var/lib/adlin/wireguard/adlin.conf > /dev/null && #grep MyIPv6= /var/lib/adlin/wireguard/adlin.conf > /dev/null &&
ip netns exec router ip a add $(sed 's/^.*MyIPv6=//p;d' /var/lib/adlin/wireguard/adlin.conf | sed "s#:[^:/]*/.*\$#:1/96#") dev ethsrv # ip netns exec router ip a add $(sed 's/^.*MyIPv6=//p;d' /var/lib/adlin/wireguard/adlin.conf | sed "s#:[^:/]*/.*\$#:1/96#") dev ethsrv
ip netns add ns ip netns add ns
ip link add vethin-ns type veth peer name veth-ns ip link add vethin-ns type veth peer name veth-ns
@ -426,13 +516,27 @@ files:
ip l add brwks type bridge ip l add brwks type bridge
ip link add veth-wks1 type veth peer name ethwks1 ip link add veth-wks1 type veth peer name ethwks1
ip link add link ethwks1 name ethwks-dg1 type vlan id 10
ip link add veth-wks2 type veth peer name ethwks2 ip link add veth-wks2 type veth peer name ethwks2
ip link add link ethwks2 name ethwks-rh1 type vlan id 11
ip link add veth-wks3 type veth peer name ethwks3
ip link add link ethwks3 name ethwks-rh2 type vlan id 11
ip link add veth-wks4 type veth peer name ethwks4
ip link add link ethwks4 name ethwks-cm1 type vlan id 12
ip link set veth-wks master brwks ip link set veth-wks master brwks
ip link set veth-wks1 master brwks ip link set veth-wks1 master brwks
ip link set veth-wks2 master brwks ip link set veth-wks2 master brwks
ip link set veth-wks3 master brwks
ip link set veth-wks4 master brwks
ip link set veth-wks up ip link set veth-wks up
ip link set veth-wks1 up ip link set veth-wks1 up
ip link set veth-wks2 up ip link set veth-wks2 up
ip link set veth-wks3 up
ip link set veth-wks4 up
ip link set ethwks1 up
ip link set ethwks2 up
ip link set ethwks3 up
ip link set ethwks4 up
ip link set brwks up ip link set brwks up
ip l | grep eth2 > /dev/null && { ip l | grep eth2 > /dev/null && {
ip link set eth2 up ip link set eth2 up
@ -443,24 +547,119 @@ files:
- path: etc/init.d/012-dl-fixes - path: etc/init.d/012-dl-fixes
contents: | contents: |
#!/bin/sh #!/bin/sh
ip netns exec router wget -O - --header "X-ADLIN-time: $(stat -c %Y /boot)" https://adlin.nemunai.re/fix-vm | sh ip netns exec router wget -q -O - --header "X-ADLIN-time: $(stat -c %Y /boot)" https://adlin.nemunai.re/fix-vm | sh
mode: "0755"
- path: etc/init.d/014-default-router-config
contents: |
#!/bin/sh
[ -d /var/lib/adlin/wrt-etc ] || {
mkdir -p /var/lib/adlin/wrt-etc
cp -r /containers/services/mainrouter/lower/etc/* /var/lib/adlin/wrt-etc/
# Configured by students
rm -f /var/lib/adlin/wrt-etc/config/firewall
touch /var/lib/adlin/wrt-etc/config/firewall
# Avoid listening on IPv6
sed -r -i '/list\s+listen_http\s+\[::\]:80/d;/list\s+listen_https\s+\[::\]:443/d' /var/lib/adlin/wrt-etc/config/uhttpd
# Configure networking
cat > /var/lib/adlin/wrt-etc/config/network <<EOF
config interface 'loopback'
option ifname 'lo'
option proto 'static'
option ipaddr '127.0.0.1'
option netmask '255.0.0.0'
config interface 'wan'
option ifname 'eth0'
option proto 'dhcp'
EOF
}
[ -e /var/lib/adlin/wrt-config ] && {
mv /var/lib/adlin/wrt-config/* /var/lib/adlin/wrt-etc/config/
rmdir /var/lib/adlin/wrt-config
}
[ -f /var/lib/adlin/wrt-firewall.user ] && mv /var/lib/adlin/wrt-firewall.user /var/lib/adlin/wrt-etc/firewall.user
[ -f /var/lib/adlin/wrt-sysctl.conf ] && mv /var/lib/adlin/wrt-sysctl.conf /var/lib/adlin/wrt-etc/sysctl.conf
# Ensure custom rules are applied
grep -q /etc/firewall.user /var/lib/adlin/wrt-etc/config/firewall || cat >> /var/lib/adlin/wrt-etc/config/firewall <<EOF
config include
option path /etc/firewall.user
EOF
[ -f /var/lib/adlin/wireguard/adlin.conf ] && /usr/bin/update-wg-conf
mode: "0755"
- path: usr/bin/update-wg-conf
contents: |
#!/bin/sh
TUNPVKEY=$(sed 's/^.*PrivateKey = //p;d' /var/lib/adlin/wireguard/adlin.conf)
TUNIP=$(sed 's/^.*MyIPv6=//p;d' /var/lib/adlin/wireguard/adlin.conf)
SRVIP=$(echo "${TUNIP}" | sed "s#:[^:/]*/.*\$#:1/96#")
WKSIP=$(echo "${TUNIP}" | sed "s#:[^:/]*/.*\$#1::1/96#")
grep -q wireguard /var/lib/adlin/wrt-etc/config/network && {
sed -i -r "s#list addresses '[^']+'#list addresses '${TUNIP}'#;s#option private_key '[^']+'#option private_key '${TUNPVKEY}'#;" /var/lib/adlin/wrt-etc/config/network
}
grep -q wireguard /var/lib/adlin/wrt-etc/config/network || cat >> /var/lib/adlin/wrt-etc/config/network <<EOF
config interface 'wg0'
option proto 'wireguard'
option force_link '1'
list addresses '${TUNIP}'
option private_key '${TUNPVKEY}'
config wireguard_wg0
option public_key 'uSpqyYovvP4OG6wDxZ0Qkq45MfyK58PMUuPaLesY8FI='
option description 'maatma'
option persistent_keepalive '5'
list allowed_ips '::/0'
option endpoint_host '82.64.31.248'
option endpoint_port '42912'
config interface 'srv'
option ifname 'ethsrv'
option proto 'static'
option netmask '255.255.255.0'
option ipaddr '172.23.42.1'
list ip6addr '${SRVIP}'
config route6
option target '::/0'
option gateway '2a01:e0a:2b:2252::1'
option interface 'wg0'
EOF
mode: "0755"
- path: etc/init.d/014-get-ssh-keys
contents: |
#!/bin/sh
# Retrieve ssh keys
[ -f /var/lib/adlin/authorized_keys ] || nsenter -n/run/netns/router -- /usr/bin/wget -O /var/lib/adlin/authorized_keys https://cri.epita.fr/$(sed 's/^.*MyLogin=//p;d' /var/lib/adlin/wireguard/adlin.conf).keys
mode: "0755" mode: "0755"
# - path: etc/init.d/021-correction # - path: etc/init.d/021-correction
# contents: | # contents: |
# #!/bin/sh # #!/bin/sh
# PS=$(pgrep systemd | head -1) # PS=$(pgrep procd | head -1)
# nsenter -t "${PS}" -a sysctl -w net.ipv4.ip_forward=1 # nsenter -t "${PS}" -a -- sysctl -w net.ipv4.ip_forward=1
# nsenter -t "${PS}" -a sysctl -w net.ipv6.conf.all.forwarding=1 # nsenter -t "${PS}" -a -- sysctl -w net.ipv6.conf.all.forwarding=1
# nsenter -t "${PS}" -a sysctl -w net.ipv4.conf.ethsrv.route_localnet=1 # nsenter -t "${PS}" -a -- sysctl -w net.ipv4.conf.ethsrv.route_localnet=1
# nsenter -t "${PS}" -a iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE # nsenter -t "${PS}" -a -- iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# nsenter -t "${PS}" -a iptables -t nat -A POSTROUTING -o ethsrv -m addrtype --src-type LOCAL -j MASQUERADE # nsenter -t "${PS}" -a -- iptables -t nat -A POSTROUTING -o ethsrv -m addrtype --src-type LOCAL -j MASQUERADE
# nsenter -t "${PS}" -a iptables -t nat -A PREROUTING -p tcp --dport 8052 -j DNAT --to 172.23.42.9 # nsenter -t "${PS}" -a -- iptables -t nat -A PREROUTING -p tcp --dport 8052 -j DNAT --to 172.23.42.9
# nsenter -t "${PS}" -a iptables -t nat -A OUTPUT -o lo -p tcp -m tcp --dport 8052 -j DNAT --to-destination 172.23.42.9 # nsenter -t "${PS}" -a -- iptables -t nat -A OUTPUT -o lo -p tcp -m tcp --dport 8052 -j DNAT --to-destination 172.23.42.9
# nsenter -t "${PS}" -a iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to 172.23.42.6 # nsenter -t "${PS}" -a -- iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to 172.23.42.6
# nsenter -t "${PS}" -a iptables -t nat -A OUTPUT -o lo -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.23.42.6 # nsenter -t "${PS}" -a -- iptables -t nat -A OUTPUT -o lo -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.23.42.6
# nsenter -t "${PS}" -a ip link set ethwks up # nsenter -t "${PS}" -a -- ip link set ethwks up
# cat <<EOF | nsenter -t "${PS}" -a tee /etc/udhcpd.conf # cat <<EOF | nsenter -t "${PS}" -a -- tee /etc/udhcpd.conf
# start 192.168.6.50 # start 192.168.6.50
# end 192.168.6.200 # end 192.168.6.200
# interface ethwks # interface ethwks
@ -471,24 +670,43 @@ files:
# EOF # EOF
# mode: "0755" # mode: "0755"
- path: /etc/init.d/999-rw-passwd.sh - path: /etc/init.d/800-rw-passwd.sh
contents: | contents: |
#!/bin/sh #!/bin/sh
sed -ri '/^root/s@^.*$@root:$6$QNuPvO59Xk4UO3le$3P0V2ef6dHlKgO1FHsKcPPgOvL.YeCOPFqfIVTtpYn5eEn3xkgGYeM1RMCQ9l/eTc6rRc.l.WeRe1iJVznVGj/:17968:0:99999:7:::@' /containers/services/mainrouter/rootfs/etc/shadow sed -ri '/^root/s@^root:x:.*$@root:$1$ChIJgCib$1IYTTG.wKCXqbo1RMEQCc0:18706:0:99999:7:::@' /var/lib/adlin/wrt-etc/shadow
cp /etc/services /containers/services/mainrouter/rootfs/etc/services mkdir -p /var/lib/adlin/wrt-etc/dropbear/
sed -ri '/^root/s@^.*$@root:$6$QNuPvO59Xk4UO3le$3P0V2ef6dHlKgO1FHsKcPPgOvL.YeCOPFqfIVTtpYn5eEn3xkgGYeM1RMCQ9l/eTc6rRc.l.WeRe1iJVznVGj/:17968:0:99999:7:::@' /containers/services/matrix/rootfs/etc/shadow [ -f /var/lib/adlin/authorized_keys ] && ! [ -f /var/lib/adlin/wrt-etc/dropbear/authorized_keys ] && cp /var/lib/adlin/authorized_keys /var/lib/adlin/wrt-etc/dropbear/authorized_keys
cp /etc/services /containers/services/matrix/rootfs/etc/services
sed -ri '/^root/s@^.*$@root:$6$QNuPvO59Xk4UO3le$3P0V2ef6dHlKgO1FHsKcPPgOvL.YeCOPFqfIVTtpYn5eEn3xkgGYeM1RMCQ9l/eTc6rRc.l.WeRe1iJVznVGj/:17968:0:99999:7:::@' /containers/services/ns-auth/rootfs/etc/shadow for svc in sshd-wks-rh1 sshd-wks-dg1
cp /etc/services /containers/services/web/rootfs/etc/services do
sed -ri '/^root/s@^.*$@root:$6$QNuPvO59Xk4UO3le$3P0V2ef6dHlKgO1FHsKcPPgOvL.YeCOPFqfIVTtpYn5eEn3xkgGYeM1RMCQ9l/eTc6rRc.l.WeRe1iJVznVGj/:17968:0:99999:7:::@' /containers/services/web/rootfs/etc/shadow mkdir -p /containers/services/${svc}/rootfs/root/.ssh
[ -f /var/lib/adlin/authorized_keys ] && cp /var/lib/adlin/authorized_keys /containers/services/${svc}/rootfs/root/.ssh/authorized_keys
done
for svc in matrix ns-auth ns-resolv web
do
sed -ri '/^root/s@^.*$@root:$6$4/xWhDY0JERkg6eg$ZKglx2TQT2ITM525di2aOhda9r9L.kUjYArPTF5pVTzi3/SRe.My4Z5Cg9vabK0ax2kZ.lLPFHA8v7jw.0N/8.:18707:0:99999:7:::@' /containers/services/${svc}/rootfs/etc/shadow
cp /etc/services /containers/services/${svc}/rootfs/etc/services
mkdir -p /containers/services/${svc}/rootfs/root/.ssh
[ -f /var/lib/adlin/authorized_keys ] && cp /var/lib/adlin/authorized_keys /containers/services/${svc}/rootfs/root/.ssh/authorized_keys
nsenter -t $(ctr -n services.linuxkit t ls | grep ${svc} | awk '{ print $2 }') -a ssh-keygen -A
done
exit 0 exit 0
mode: "0555" mode: "0555"
- path: /etc/init.d/850-later-use.sh
contents: |
#!/bin/sh
# This file is currently not used and is reserved for future use.
mode: "0755"
- path: /etc/init.d/999-import-feeds.sh - path: /etc/init.d/999-import-feeds.sh
contents: | contents: |
#!/bin/sh #!/bin/sh
sleep 20 sleep 20
nsenter -t $(pgrep systemd | head -1) -a curl -s -u adeline:adlin2021 -d @- http://172.23.42.6:8080/v1/import < /root/feeds.opml 2> /dev/null > /dev/null nsenter -t $(pgrep procd | head -1) -a -- curl -s -u adeline:adlin2022 -d @- http://172.23.42.6:8080/v1/import < /root/feeds.opml 2> /dev/null > /dev/null
exit 0 exit 0
mode: "0555" mode: "0555"
@ -496,15 +714,18 @@ files:
source: pkg/debian-tuto3/issue source: pkg/debian-tuto3/issue
mode: "0444" mode: "0444"
- path: /etc/init.d/500-showip.sh - path: /etc/init.d/900-showip.sh
contents: | contents: |
#!/bin/sh #!/bin/sh
echo
cat /etc/issue.adlin # Wait wg0
echo nsenter -n/run/netns/router -- ip a show dev wg0 2> /dev/null > /dev/null || sleep 1
nsenter -n/run/netns/router ip -c a show dev wg0 2> /dev/null || nsenter -n/run/netns/router /usr/bin/ask.sh nsenter -n/run/netns/router -- ip a show dev wg0 2> /dev/null > /dev/null || sleep 1
nsenter -n/run/netns/router ip -c a show dev eth0 nsenter -n/run/netns/router -- ip a show dev wg0 2> /dev/null > /dev/null || sleep 1
nsenter -n/run/netns/wks1 ip -c a show dev eth1 2> /dev/null || echo "Attachez une seconde carte ethernet à la VM pour pouvoir vous connecter à un poste de travail." nsenter -n/run/netns/router -- ip a show dev wg0 2> /dev/null > /dev/null || sleep 1
nsenter -n/run/netns/router -- ip a show dev wg0 2> /dev/null > /dev/null || sleep 1
/usr/bin/welcome
exit 0 exit 0
mode: "0555" mode: "0555"
@ -521,13 +742,18 @@ files:
- path: /usr/bin/welcome - path: /usr/bin/welcome
contents: | contents: |
#!/bin/sh #!/bin/sh
/etc/init.d/500-showip.sh echo
cat /etc/issue.adlin
echo
nsenter -n/run/netns/router -- ip -c a show dev wg0 2> /dev/null || nsenter -n/run/netns/router /usr/bin/ask.sh
nsenter -n/run/netns/router -- ip -c a show dev eth0
nsenter -n/run/netns/wks-rh1 -- ip -c a show dev eth1 2> /dev/null || echo "Attachez une seconde carte ethernet à la VM pour pouvoir vous connecter à un poste de travail."
mode: "0755" mode: "0755"
- path: /usr/sbin/sos-dhcp - path: /usr/sbin/sos-dhcp
contents: | contents: |
#!/bin/sh #!/bin/sh
nsenter -t $(pgrep dhcpcd) -a dhcpcd nsenter -t $(pgrep procd) -a -- udhcpc -i eth0
mode: "0755" mode: "0755"
- path: /usr/sbin/raz-my-dd - path: /usr/sbin/raz-my-dd
@ -535,12 +761,12 @@ files:
#!/bin/sh #!/bin/sh
echo -n "Are you sure? Press Enter to continue... " echo -n "Are you sure? Press Enter to continue... "
read -s read -s
dd if=/dev/zero of=/dev/sda size=10 bs=4096 dd if=/dev/zero of=/dev/sda count=10 bs=4096
sync sync
reboot -f reboot -f
mode: "0755" mode: "0755"
- path: /usr/sbin/join-p0m - path: /usr/sbin/join-maatma
contents: | contents: |
#!/bin/sh #!/bin/sh
[ -s "/var/lib/adlin/wireguard/adlin.token" ] && echo "A token is already defined. You'll erase it it you continue." [ -s "/var/lib/adlin/wireguard/adlin.token" ] && echo "A token is already defined. You'll erase it it you continue."
@ -548,7 +774,8 @@ files:
read WGTOKEN read WGTOKEN
mkdir -p /var/lib/adlin/wireguard/ mkdir -p /var/lib/adlin/wireguard/
echo $WGTOKEN > /var/lib/adlin/wireguard/adlin.token echo $WGTOKEN > /var/lib/adlin/wireguard/adlin.token
echo "Token saved. You need to reboot now." nsenter -n/run/netns/router /usr/bin/ask.sh && /usr/bin/update-wg-conf && nsenter -t $(pgrep procd) -a -- /etc/init.d/network restart
echo "Token saved. You should reboot now."
mode: "0755" mode: "0755"
- path: /usr/sbin/diagnostic - path: /usr/sbin/diagnostic
@ -562,10 +789,10 @@ files:
echo -n "Disque dur monté : "; df /var/lib/adlin/ | grep ^/dev/sd > /dev/null && ok || ko echo -n "Disque dur monté : "; df /var/lib/adlin/ | grep ^/dev/sd > /dev/null && ok || ko
echo echo
echo -n "Token Maatma renseigné : "; [ -s "/var/lib/adlin/wireguard/adlin.token" ] && ok -n || ko -n echo -n "Token Maatma renseigné : "; [ -s "/var/lib/adlin/wireguard/adlin.token" ] && ok -n || ko -n
echo -n " - Tunnel monté : "; nsenter -n/run/netns/router /usr/bin/wg show wg0 > /dev/null 2> /dev/null && ok -n || ko -n echo -n " - Tunnel monté : "; nsenter -n/run/netns/router -- /usr/bin/wg show wg0 > /dev/null 2> /dev/null && ok -n || ko -n
echo -n " - Tunnel établit : "; [ "$(nsenter -n/run/netns/router /usr/bin/wg show wg0 dump | tail -1 | cut -f 6 2> /dev/null)" != "0" ] && ok || ko nsenter -n/run/netns/router -- /usr/bin/wg show wg0 > /dev/null 2> /dev/null && echo -n " - Tunnel établi : "; [ "$(nsenter -n/run/netns/router -- /usr/bin/wg show wg0 dump | tail -1 | cut -f 6 2> /dev/null)" != "0" ] && ok || ko
echo -n "Ping Gateway Maatma : "; nsenter -n/run/netns/router ping -w 2 -c 1 2a01:e0a:2b:2252::1 > /dev/null 2> /dev/null && ok -n || ko -n echo -n "Ping Gateway Maatma : "; nsenter -n/run/netns/router -- ping -w 2 -c 1 2a01:e0a:2b:2252::1 > /dev/null 2> /dev/null && ok -n || ko -n
echo -n " - Ping Internet IPv4 : "; nsenter -n/run/netns/router ping -w 2 -c 1 1.1.1.1 > /dev/null 2> /dev/null && ok || ko echo -n " - Ping Internet IPv4 : "; nsenter -n/run/netns/router -- ping -w 2 -c 1 1.1.1.1 > /dev/null 2> /dev/null && ok || ko
echo echo
echo -n "États serveurs : "; echo -n "États serveurs : ";
ctr -n services.linuxkit t ls | grep mainrouter | grep RUNNING > /dev/null && ok -n "Routeur" || ko -n "Routeur" ctr -n services.linuxkit t ls | grep mainrouter | grep RUNNING > /dev/null && ok -n "Routeur" || ko -n "Routeur"
@ -584,13 +811,23 @@ files:
echo echo
echo echo
echo -n "États Workstations : " echo -n "États Workstations : "
ctr -n services.linuxkit t ls | grep dhcpcd-wks1 | grep RUNNING > /dev/null && ok -n "WKS-1" || ko -n "WKS-1" ctr -n services.linuxkit t ls | grep dhcpcd-wks-dg1 | grep RUNNING > /dev/null && ok -n "WKS-DG1" || ko -n "WKS-DG1"
echo -n "(" echo -n "("
ctr -n services.linuxkit t ls | grep sshd-wks1 | grep RUNNING > /dev/null && ok -n "SSH" || ko -n "SSH" ctr -n services.linuxkit t ls | grep sshd-wks-dg1 | grep RUNNING > /dev/null && ok -n "SSH" || ko -n "SSH"
echo -n " "
ctr -n services.linuxkit t ls | grep minichecker-wks-dg1 | grep RUNNING > /dev/null && ok -n "CK" || ko -n "CK"
echo -n ") " echo -n ") "
ctr -n services.linuxkit t ls | grep dhcpcd-wks2 | grep RUNNING > /dev/null && ok -n "WKS-2" || ko -n "WKS-2" ctr -n services.linuxkit t ls | grep dhcpcd-wks-rh1 | grep RUNNING > /dev/null && ok -n "WKS-RH1" || ko -n "WKS-RH1"
echo -n "(" echo -n "("
ctr -n services.linuxkit t ls | grep sshd-wks2 | grep RUNNING > /dev/null && ok -n "SSH" || ko -n "SSH" ctr -n services.linuxkit t ls | grep sshd-wks-rh1 | grep RUNNING > /dev/null && ok -n "SSH" || ko -n "SSH"
echo -n ") "
ctr -n services.linuxkit t ls | grep dhcpcd-wks-rh2 | grep RUNNING > /dev/null && ok -n "WKS-RH2" || ko -n "WKS-RH2"
echo -n "("
ctr -n services.linuxkit t ls | grep minichecker-wks-rh2 | grep RUNNING > /dev/null && ok -n "CK" || ko -n "CK"
echo -n ") "
ctr -n services.linuxkit t ls | grep dhcpcd-wks-cm1 | grep RUNNING > /dev/null && ok -n "WKS-CM1" || ko -n "WKS-CM1"
echo -n "("
ctr -n services.linuxkit t ls | grep minichecker-wks-cm1 | grep RUNNING > /dev/null && ok -n "CK" || ko -n "CK"
echo -n ") " echo -n ") "
echo echo
echo echo
@ -630,6 +867,7 @@ files:
log-queries: yes log-queries: yes
log-replies: yes log-replies: yes
use-syslog: no use-syslog: no
logfile: "/var/log/unbound.log"
hide-identity: yes hide-identity: yes
hide-version: yes hide-version: yes
qname-minimisation: yes qname-minimisation: yes
@ -648,6 +886,23 @@ files:
forward-addr: 2606:4700:4700::1111 forward-addr: 2606:4700:4700::1111
mode: "0440" mode: "0440"
- path: etc/rinittab
contents: |
::sysinit:/etc/init.d/rcS S boot
::shutdown:/etc/init.d/rcS K shutdown
mode: "0644"
- path: etc/rshadow
contents: |
root:$1$ChIJgCib$1IYTTG.wKCXqbo1RMEQCc0:18706:0:99999:7:::
daemon:*:0:0:99999:7:::
ftp:*:0:0:99999:7:::
network:*:0:0:99999:7:::
nobody:*:0:0:99999:7:::
dnsmasq:x:0:0:99999:7:::
mode: "0640"
- path: etc/wpasswd - path: etc/wpasswd
contents: | contents: |
root:x:0:0:root:/root:/bin/bash root:x:0:0:root:/root:/bin/bash
@ -676,10 +931,9 @@ files:
systemd-bus-proxy:x:106:108:systemd Bus Proxy,,,:/run/systemd:/bin/false systemd-bus-proxy:x:106:108:systemd Bus Proxy,,,:/run/systemd:/bin/false
mode: "0644" mode: "0644"
- path: etc/wshadow - path: etc/wshadow
contents: | contents: |
root:$6$QNuPvO59Xk4UO3le$3P0V2ef6dHlKgO1FHsKcPPgOvL.YeCOPFqfIVTtpYn5eEn3xkgGYeM1RMCQ9l/eTc6rRc.l.WeRe1iJVznVGj/:17968:0:99999:7::: root:$6$4/xWhDY0JERkg6eg$ZKglx2TQT2ITM525di2aOhda9r9L.kUjYArPTF5pVTzi3/SRe.My4Z5Cg9vabK0ax2kZ.lLPFHA8v7jw.0N/8.:18707:0:99999:7:::
daemon:*:17575:0:99999:7::: daemon:*:17575:0:99999:7:::
bin:*:17575:0:99999:7::: bin:*:17575:0:99999:7:::
sys:*:17575:0:99999:7::: sys:*:17575:0:99999:7:::
@ -722,6 +976,85 @@ files:
nameserver 2620:fe::fe nameserver 2620:fe::fe
mode: "0644" mode: "0644"
- path: etc/rsysctl.conf
contents: |
# Do not edit, changes to this file will be lost on upgrades
# /etc/sysctl.conf can be used to customize sysctl settings
kernel.panic=3
kernel.core_pattern=/tmp/%e.%t.%p.%s.core
fs.suid_dumpable=2
fs.protected_hardlinks=1
fs.protected_symlinks=1
net.core.bpf_jit_enable=1
net.ipv4.conf.default.arp_ignore=1
net.ipv4.conf.all.arp_ignore=1
net.ipv4.icmp_echo_ignore_broadcasts=1
net.ipv4.icmp_ignore_bogus_error_responses=1
net.ipv4.igmp_max_memberships=100
net.ipv4.tcp_fin_timeout=30
net.ipv4.tcp_keepalive_time=120
net.ipv4.tcp_syncookies=1
net.ipv4.tcp_timestamps=1
net.ipv4.tcp_sack=1
net.ipv4.tcp_dsack=1
mode: "0644"
- path: etc/rpreinit
contents: |
#!/bin/sh
# Copyright (C) 2006-2015 OpenWrt.org
# Copyright (C) 2010 Vertical Communications
mkdir -p /var/lock
mount -t tmpfs none /var/lock
unset PREINIT
exec /sbin/procd
mode: "0755"
- path: lib/preinit/20_check_iso
contents: |
#!/bin/sh
# Copyright (C) 2006-2015 OpenWrt.org
# Copyright (C) 2010 Vertical Communications
check_for_iso() {
echo > /dev/null || ramoverlay
}
boot_hook_add preinit_mount_root check_for_iso
mode: "0644"
- path: lib/preinit/30_failsafe_wait
contents: |
#!/bin/sh
# Copyright (C) 2006-2015 OpenWrt.org
# Copyright (C) 2010 Vertical Communications
mode: "0644"
- path: lib/preinit/99_10_failsafe_login
contents: |
#!/bin/sh
# Copyright (C) 2006-2015 OpenWrt.org
# Copyright (C) 2010 Vertical Communications
failsafe_netlogin () {
dropbearkey -t rsa -s 1024 -f /tmp/dropbear_failsafe_host_key
dropbear -r /tmp/dropbear_failsafe_host_key <> /dev/null 2>&1
}
failsafe_shell() {
echo > /dev/null || ramoverlay
}
boot_hook_add failsafe failsafe_netlogin
boot_hook_add failsafe failsafe_shell
mode: "0644"
trust: trust:
org: org:
- linuxkit - linuxkit

View File

@ -1,23 +1,30 @@
\newpage \newpage
Netfilter Routage
========= =======
Le projet `netfilter`[^netfilter] est l'implémentation de pare-feu au sein du Votre entreprise dispose d'un modeste routeur utilisant
noyau Linux. Il s'agit d'un mécanisme de filtrage des paquets réseau basés sur [OpenWrt](https://openwrt.org/). Il s'agit d'une petite distribution Linux
des règles, chargées par l'espace utilisateur dans le noyau. On utilise pour mettant à disposition une interface web pour configurer son routeur
cela les programmes `nft` (du projet `nftables`), ou de manière historique facilement[^facilement].
`iptables`.
[^netfilter]: <https://netfilter.org/> [^facilement]: Si vous préférez, ce TP existe aussi en utilisant une simple
distribution Debian comme routeur. C'est tout aussi efficace et les mêmes
technologies sont en jeu. Demandez à votre professeur l'ISO si vous êtes
intéressés !
Au sein du noyau Linux, le [projet `netfilter`](https://netfilter.org/) est
l'implémentation de pare-feu standard. Il s'agit d'un mécanisme de filtrage des
paquets réseau basés sur des règles, chargées par l'espace utilisateur dans le
noyau. On utilise pour cela les programmes `nft` (du projet `nftables`), ou de
manière historique `iptables`.
Les deux projets ont une manière de fonctionner très similaire, mais il est Les deux projets ont une manière de fonctionner très similaire, mais il est
important de ne pas les utiliser en même temps, sous peine de voir apparaître important de ne pas les utiliser en même temps, sous peine de voir apparaître
des problèmes incompréhensible à déboguer, plus ou moins aléatoirement. des problèmes incompréhensible à déboguer, plus ou moins aléatoirement.
Réseau fonctionnel ? ## Réseau fonctionnel ?
--------------------
Première étape : avez-vous vérifié l'état du réseau sur le routeur ? Première étape : avez-vous vérifié l'état du réseau sur le routeur ?
@ -35,8 +42,7 @@ que vous devriez obtenir sont :
contacter. contacter.
Donner accès à Internet ## Donner accès à Internet
-----------------------
Votre administrateur système vous assure que le serveur de noms est bien lancé Votre administrateur système vous assure que le serveur de noms est bien lancé
et configuré comme demandé. et configuré comme demandé.
@ -59,9 +65,53 @@ Test à passer :
``` ```
</div> </div>
Vous pouvez utiliser, par exemple `tcpdump`, pour comprendre ce qu'il se passe
sur votre routeur :
Exposer un service web sur Internet <div lang="en-US">
----------------------------------- ```
router# tcpdump -i ethsrv
router# tcpdump -i eth0 udp and port 53
```
</div>
#### Attention : {-}
Le serveur DNS résolveur met en cache les problèmes qu'il rencontre. Il vous
faudra sans doute patienter une bonne minute, une fois que vous aurez la bonne
configuration, afin qu'il tente à nouveau de contacter un serveur de noms pour
faire une résolution. C'est un comportement normal.
Depuis l'ISO en version 3.1, vous pouvez vous connecter sur la machine
hébergeant le résolveur afin de le redémarrer manuellement.
## Accéder aux autres serveurs du parc
Depuis le routeur, vous pouvez vous SSH en utilisant le nom d'hôte attribué aux
machines :
<div lang="en-US">
- `ssh root@news`
- `ssh root@matrix`
- `ssh root@web`
</div>
Depuis l'extérieur, vous devez utiliser le routeur comme *bastion*. Avec SSH,
utilisez l'option `-J` pour désigner une machine intermédiaire qui servira à
accéder à la machine cible :
<div lang="en-US">
```
42sh$ ssh -J root@$EXT_ROUTER root@172.23.42.3
```
</div>
## Exposer les services
### Localement
Vous avez compris comment vos machines peuvent accéder à Internet sans avoir Vous avez compris comment vos machines peuvent accéder à Internet sans avoir
pour autant d'IP routable sur Internet. Cependant, si cela répond parfaitement pour autant d'IP routable sur Internet. Cependant, si cela répond parfaitement
@ -73,13 +123,16 @@ depuis l'interface externe du routeur. Après configuration, depuis un
navigateur sur votre poste, vous devriez pouvoir accéder à : navigateur sur votre poste, vous devriez pouvoir accéder à :
<div lang="en-US"> <div lang="en-US">
* `http://$EXT_ROUTER_IP:80/` : Vitrine * `http://$EXT_ROUTER_IP:8000/` : Vitrine
* `http://$EXT_ROUTER_IP:8080/` : Miniflux * `http://$EXT_ROUTER_IP:8080/` : Miniflux
* `http://$EXT_ROUTER_IP:8448/` : Matrix * `http://$EXT_ROUTER_IP:8008/` : Matrix
</div> </div>
Notez bien qu'il s'agit là seulement d'un test avec l'IPv4 de votre routeur. Il
n'est pas encore demandé de faire cela sur l'IPv6 routable sur Internet.
### Miniflux
### Utiliser Miniflux
Utilisez le nom d'utilisateur `adeline` pour vous connecter à Utilisez le nom d'utilisateur `adeline` pour vous connecter à
miniflux. N'oubliez pas de changer le mot de passe avant que quelqu'un miniflux. N'oubliez pas de changer le mot de passe avant que quelqu'un
@ -88,3 +141,11 @@ d'autre s'en charge à votre place !
Si vos serveurs ont bien accès à Internet, vous pourrez mettre à jour Si vos serveurs ont bien accès à Internet, vous pourrez mettre à jour
la liste des flux pré-enregistrés dans miniflux, afin de faire un peu la liste des flux pré-enregistrés dans miniflux, afin de faire un peu
de veille ! de veille !
### On passe sur Internet ? (bonus)
Si jusque là, tout se passe à merveille pour vous (c'est ce que je vous
souhaite !), vous pouvez maintenant rediriger le port 80 et 443 arrivant sur
l'IPv6 de votre routeur, vers ceux du serveur web. Sur lequel nous allons
installer un reverse-proxy...

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 118 KiB

View File

@ -3,14 +3,14 @@ title: Administration Linux avancée -- TP n^o^ 3
subtitle: subtitle:
author: Pierre-Olivier *nemunaire* [Mercier]{.smallcaps} author: Pierre-Olivier *nemunaire* [Mercier]{.smallcaps}
institute: EPITA institute: EPITA
date: Lundi 30 mars 2020 date: Lundi 22 mars 2021
abstract: | abstract: |
Durant ce troisième TP, nous allons faire un peu plus de réseau ! Durant ce troisième TP, nous allons faire un peu plus de réseau !
\vspace{1em} \vspace{1em}
Tous les éléments de ce TP (exercices et projet) sont à rendre à Tous les éléments de ce TP (exercices et projet) sont à rendre à
<adlin@nemunai.re> au plus tard le dimanche 12 avril 2019 à 23 <adlin@nemunai.re> au plus tard le dimanche 11 avril 2021 à 23
h 42. Consultez la dernière section de chaque partie pour plus d'information h 42. Consultez la dernière section de chaque partie pour plus d'information
sur les éléments à rendre. sur les éléments à rendre.

View File

@ -7,24 +7,32 @@ Présentation du système d'information
------------------------------------- -------------------------------------
Le système d'information que vous allez avoir à gérer aujourd'hui est de taille Le système d'information que vous allez avoir à gérer aujourd'hui est de taille
moyenne : vous aurez en votre possession un serveur DNS résolveur, un serveur moyenne. Vous aurez en votre possession :
DNS autoritaire, un serveur de base de données ainsi que plusieurs serveurs web
(servant respectivement votre vitrine, [Miniflux](https://miniflux.app/), ainsi - un serveur DNS résolveur,
que [Matrix](https://matrix.org/)). - un serveur DNS faisant autorité,
- un serveur de base de données,
- plusieurs serveurs web (servant respectivement votre vitrine,
[Miniflux](https://miniflux.app/), ainsi que [Matrix](https://matrix.org/)),
- de nombreux postes de travail.
Vous êtes l'administrateur réseau de l'entreprise et l'on vous demande de Vous êtes l'administrateur réseau de l'entreprise et l'on vous demande de
connecter tous ces services **correctement**. connecter tous ces services **correctement**.
Voici un schéma de l'infrastructure complète dont vous allez disposer en
démarrant l'ISO.
![Architecture réseau à produire](topologie.png "Topologie")
L'image ISO que vous avez récupérée met à votre disposition tout ce système L'image ISO que vous avez récupérée met à votre disposition tout ce système
d'information, déjà en partie configuré pour sa partie logicielle, il ne reste d'information, déjà en partie configuré pour sa partie logicielle, il ne reste
plus qu'à éditer la configuration du routeur. plus qu'à éditer la configuration du routeur.
![Architecture réseau à produire](topologie.png "Topologie") Attention, contrairement au précédent TP, la majorité des modifications que
vous allez effectuer ne seront pas persistantes d'un reboot à l'autre. À chaque
Attention, contrairement au précédent TP, tout se fait en direct, il n'y a redémarrage de la machine virtuelle, vous retomberez dans un état initial.
aucune sauvegarde effectuée : à chaque redémarrage de la machine virtuelle, Seuls quelques éléments comme le token de votre tunnel, la configuration du
vous retomberez dans l'état initial : seuls quelques éléments comme le token de routeur et le contenu de la base de données persistent.
votre tunnel et le contenu de la base de données.
Accéder à la machine virtuelle Accéder à la machine virtuelle
------------------------------ ------------------------------
@ -33,7 +41,7 @@ Une fois la machine virtuelle démarrée, vous devriez voir apparaître l'IP qu'
obtenue la machine sur votre réseau : obtenue la machine sur votre réseau :
``` ```
You didn't define your token to connect the network. Please run here `join-p0m` and then reboot. You didn't define your token to connect the network. Please run here `join-maatma` and then reboot.
4: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 4: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 42:2c:63:f1:5a:49 brd ff:ff:ff:ff:ff:ff link/ether 42:2c:63:f1:5a:49 brd ff:ff:ff:ff:ff:ff
inet 10.42.23.211/24 brd 10.42.23.255 scope global eth0 inet 10.42.23.211/24 brd 10.42.23.255 scope global eth0
@ -50,15 +58,11 @@ Une ligne de commande est disponible au sein de la machine virtuelle à des fins
de débogage, si nécessaire. Vous ne devriez normalement pas avoir à interagir de débogage, si nécessaire. Vous ne devriez normalement pas avoir à interagir
avec celle-ci. avec celle-ci.
Si vous assignez deux cartes réseau à la machine virtuelle, vous devriez voir
apparaître l'IP de la carte `eth1` en dessous. Il s'agit d'une interface de
station de travail.
### Tunnel Maatma ### Tunnel Maatma
Pour retrouver votre tunnel sur Internet, vous devez, dans la console de la Pour retrouver votre tunnel sur Internet, vous devez, dans la console de la
machine virtuelle, utiliser la commande `join-p0m`. machine virtuelle, utiliser la commande `join-maatma`.
Vous pouvez aussi écrire directement dans le fichier persistant : Vous pouvez aussi écrire directement dans le fichier persistant :
@ -68,13 +72,21 @@ Vous pouvez aussi écrire directement dans le fichier persistant :
``` ```
</div> </div>
Une fois le token renseigné, vous devez redémarrer la machine afin qu'il soit
pris en compte.
### Connexions SSH ### Connexions SSH
Vous pouvez vous connecter en utilisant le compte `root` et le mot de passe Vous pouvez vous connecter en utilisant le compte `root` et le mot de passe
`adlin2021`. `adlin2022`. Comme au précédent TP, si vous disposez d'une ou plusieurs [clefs
SSH enregistrées au CRI](https://cri.epita.fr/users/nemunaire/ssh-keys/),
celles-ci sont automatiquement ajoutées aux différents serveurs. Cependant,
seuls les clefs RSA et DSA sont utilisables pour se connecter sur le routeur,
le serveur SSH ne gère pas les courbes éliptiques.
Notez que vous n'avez pas accès à la machine hébergeant la base de données, ni Notez que vous n'avez pas accès à la machine hébergeant la base de données, le
à celle du résolveur DNS. lecteur de flux RSS, ni à celle du résolveur DNS.
Objectif du TP Objectif du TP
@ -89,3 +101,53 @@ s'assurer que ce soit également le cas des stations de travail).
Étant donné le caractère éphémère de vos actions, la réalisation d'un Étant donné le caractère éphémère de vos actions, la réalisation d'un
*Playbook* Ansible semble plutôt adaptée ! *Playbook* Ansible semble plutôt adaptée !
Au secours ça ne marche pas !
-----------------------------
Pas de panique !
Quelques commandes sont à votre disposition dans le shell de la machine
virtuelle afin de vérifier que tout fonctionne correctement.
### Monitoring
Utilisez la commande `diagnostic` afin d'avoir une vue d'ensemble des éventuel
problèmes.
Tout est vert ? Toutes les machines sont opérationnelles !
Une ou plusieurs machines sont rouges ? il y a effectivement un problème avec
les machines concernées. Tentez de redémarrer une fois.
Si le problème persiste, vous pouvez formater votre disque en utilisant la
commande `raz-my-dd`. Ce qui vous permettra de retrouver la configuration
d'origine.
Pour les plus téméraires, les journaux des machines sont regroupés dans
`/var/log` accessible uniquement dans la console de la machine virtuelle.
### Retrouver mes IP
Vous ne pouvez pas simplement taper `ip a` dans le terminal de votre machine
virtuelle. Utilisez plutôt la commande `welcome` qui affichera à nouveau le
message d'accueil avec les différentes IP associées à vos machines.
### Rejoindre Maatma
Utilisez la commande `join-maatma` dans la console de la machine virtuelle,
puis redémarrez la machine.
Vous pouvez aussi passer par l'interface de votre routeur pour ajouter une
interface 'Wireguard VPN'. Utilisez les informations contenues sur la page
[Tunnels de Maatma](https://adlin.nemunai.re/maatma/tunnels) pour remplir les
différents champs.
### `join-maatma` retourne une erreur 400
Vérifiez votre token, il n'est pas valide.

View File

@ -24,13 +24,8 @@ N'ayant pas, pour le moment, d'IPv6 sur votre réseau ; vous devez mettre en
place un serveur DHCP sur votre réseau afin que vos collaborateurs puissent place un serveur DHCP sur votre réseau afin que vos collaborateurs puissent
utiliser facilement le réseau. utiliser facilement le réseau.
Configurez un serveur DHCP, tel quel `isc-dhcp-server` ou `udhcpd` afin de
distribuer des IP correspondant au plan d'adressage. N'oubliez pas de définir
le chemin permettant de sortir sur Internet ainsi que d'utiliser le résolveur
de noms de domaine local.
Une fois configuré, vous pouvez tenter de vous connecter aux services web (vous Une fois configuré, vous pouvez tenter de vous connecter aux services web (vous
devriez avoir `wget` sur la station de travail accessible). devriez avoir `wget` sur les stations de travail accessibles).
Zone démilitarisée et filtrage Zone démilitarisée et filtrage