Skip to content

Commit

Permalink
update: pod verified pod ip detection
Browse files Browse the repository at this point in the history
  • Loading branch information
Esonhugh committed Jun 1, 2024
1 parent 38c002b commit 8a2a14a
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 26 deletions.
87 changes: 87 additions & 0 deletions cmd/neighbor/neighbor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package neighbor

import (
"bufio"
"fmt"
"net"
"os"
"strings"

cmdx "github.com/esonhugh/k8spider/cmd"
"github.com/esonhugh/k8spider/define"
"github.com/esonhugh/k8spider/pkg"
"github.com/esonhugh/k8spider/pkg/mutli"
"github.com/esonhugh/k8spider/pkg/printer"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

var Opts = struct {
NamespaceWordlist string
NamespaceList []string
PodCidr string
}{}

func init() {
cmdx.RootCmd.AddCommand(NeighborCmd)
NeighborCmd.Flags().StringVar(&Opts.NamespaceWordlist, "ns-file", "", "namespace wordlist file")
NeighborCmd.Flags().StringSliceVar(&Opts.NamespaceList, "ns", []string{}, "namespace list")
NeighborCmd.Flags().StringVarP(&Opts.PodCidr, "pod-cidr", "p", defaultPodCidr(), "pod cidr list, watch out for the network interface name, default is eth0")
}

func defaultPodCidr() string {
interfaces, _ := net.Interfaces()
for _, i := range interfaces {
if i.Name == "eth0" {
addrs, _ := i.Addrs()
if addrs != nil || len(addrs) > 0 {
ip := strings.Split(addrs[0].String(), "/")[0]
return fmt.Sprintf("%v/16", ip)
}
}
}
return "10.0.0.1/16"
}

var NeighborCmd = &cobra.Command{
Use: "neighbor",
Short: "neighbor is a tool to discover k8s pod and available ip in subnet (require k8s coredns with pod verified config)",
Aliases: []string{"n", "nei"},
Run: func(cmd *cobra.Command, args []string) {
if !pkg.TestPodVerified() {
log.Fatalf("k8s coredns with pod verified config could not be set")
}
if Opts.NamespaceWordlist != "" {
f, e := os.OpenFile(Opts.NamespaceWordlist, os.O_RDONLY, 0666)
if e != nil {
log.Fatalf("open file %v failed: %v", Opts.NamespaceWordlist, e)
}
defer f.Close()
fileScanner := bufio.NewScanner(f)
fileScanner.Split(bufio.ScanLines)
for fileScanner.Scan() {
Opts.NamespaceList = append(Opts.NamespaceList, fileScanner.Text())
}
}
log.Tracef("namespace list: %v", Opts.NamespaceList)
ipNets, err := pkg.ParseStringToIPNet(Opts.PodCidr)
if err != nil {
log.Warnf("ParseStringToIPNet failed: %v", err)
return
}
r := RunMultiThread(Opts.NamespaceList, ipNets, cmdx.Opts.ThreadingNum)
printer.PrintResult(r, cmdx.Opts.OutputFile)
},
}

func RunMultiThread(ns []string, net *net.IPNet, num int) (finalRecord define.Records) {
scan := mutli.ScanNeighbor(ns, net, num)
for r := range scan {
finalRecord = append(finalRecord, r...)
}
if len(finalRecord) == 0 {
log.Warn("ScanSubnet Found Nothing")
return
}
return
}
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ var RootCmd = &cobra.Command{
},
}
}
pkg.Zone = Opts.Zone
},
Run: func(cmd *cobra.Command, args []string) {
_ = cmd.Help()
Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/esonhugh/k8spider/cmd"
_ "github.com/esonhugh/k8spider/cmd/all"
_ "github.com/esonhugh/k8spider/cmd/axfr"
_ "github.com/esonhugh/k8spider/cmd/neighbor"
_ "github.com/esonhugh/k8spider/cmd/service"
_ "github.com/esonhugh/k8spider/cmd/subnet"
_ "github.com/esonhugh/k8spider/cmd/wildcard"
Expand Down
10 changes: 6 additions & 4 deletions pkg/mutli/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ func ScanAll(subnet *net.IPNet, num int) (result <-chan []define.Record) {
return result
}

func ScanNeighbor(subnet *net.IPNet, num int) (result <-chan []define.Record) {
subs := NewSubnetScanner(num)
result = subs.ScanSubnet(subnet)
return result
func ScanNeighbor(namespace []string, subnet *net.IPNet, num int) <-chan []define.Record {
subs := NewNeighborScanner(num)
if len(namespace) == 1 {
return subs.ScanSingleNeighbor(namespace[0], subnet)
}
return subs.ScanMultiNeighbor(namespace, subnet)
}
59 changes: 57 additions & 2 deletions pkg/mutli/neigbhor.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package mutli

import (
"fmt"
"net"
"sync"
"time"

"github.com/esonhugh/k8spider/define"
"github.com/esonhugh/k8spider/pkg"
"github.com/esonhugh/k8spider/pkg/scanner"
log "github.com/sirupsen/logrus"
)

type NeighborScanner struct {
Expand All @@ -25,6 +30,56 @@ func NewNeighborScanner(threading ...int) *NeighborScanner {
}
}

func (s *NeighborScanner) ScanNeighbor(subnet *net.IPNet) <-chan []define.Record {
return nil // todo: implement this
func (s *NeighborScanner) ScanSingleNeighbor(ns string, subnet *net.IPNet) <-chan []define.Record {
if subnet == nil {
log.Debugf("subnet is nil")
return nil
}
out := make(chan []define.Record, 100)
go func() {
// if subnets, err := pkg.SubnetShift(subnet, 4); err != nil {
if subnets, err := pkg.SubnetInto(subnet, s.count); err != nil {
log.Errorf("Subnet split into %v failed, fallback to single mode, reason: %v", s.count, err)
go s.scan(ns, subnet, out)
} else {
log.Debugf("Subnet split into %v success", len(subnets))
for _, sn := range subnets {
go s.scan(ns, sn, out)
}
}
time.Sleep(10 * time.Millisecond) // wait for all goroutines to start
s.wg.Wait()
close(out)
}()
return out
}

func (s *NeighborScanner) ScanMultiNeighbor(nss []string, subnet *net.IPNet) <-chan []define.Record {
out := make(chan []define.Record, 100)
go func() {
for _, ns := range nss {
go s.scan(ns, subnet, out)
}
time.Sleep(10 * time.Millisecond) // wait for all goroutines to start
s.wg.Wait()
close(out)
}()
return out
}

func (s *NeighborScanner) scan(ns string, subnet *net.IPNet, to chan []define.Record) {
s.wg.Add(1)
// to <- scanner.ScanSubnet(subnet)
for _, ip := range pkg.ParseIPNetToIPs(subnet) {
if scanner.ScanPodExist(ip, ns) {
newRecord := define.Record{
Ip: ip,
Extra: fmt.Sprintf("%v. 0 IN A %v", pkg.IPtoPodHostName(ip.String(), ns), ip.String()),
}
to <- []define.Record{newRecord}
} else {
continue
}
}
s.wg.Done()
}
2 changes: 1 addition & 1 deletion pkg/post/records_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func TestRecordsDump(t *testing.T) {
rs, err := scanner.DumpAXFR("zonetransfer.me.", "81.4.108.41:53")
rs, err := scanner.DumpAXFR("zonetransfer.me.", "34.225.33.2:53")
if err != nil {
t.Errorf("DumpAXFR failed: %v", err)
}
Expand Down
30 changes: 13 additions & 17 deletions pkg/scanner/neigbhor.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
package scanner

import (
"net"

"github.com/esonhugh/k8spider/pkg"
log "github.com/sirupsen/logrus"
)

func TestPodVerified(zone string) bool {
iplist := []string{
"8.8.8.8",
"1.1.1.1",
"114.114.114.114",
func ScanPodExist(ip net.IP, ns string) bool {
targetHostName := pkg.IPtoPodHostName(ip.String(), ns)
ips, err := pkg.ARecord(targetHostName)
if err != nil {
log.Tracef("ScanPodExist %v failed: %v", ip.String(), err)
return false
}
for _, ip := range iplist {
targetHostName := pkg.IPtoPodHostName(ip, zone)
ips, err := pkg.ARecord(targetHostName)
if err != nil {
continue
}
// all of this ip should not return correct ip if verified is set.
for _, i := range ips {
if i.String() == ip {
return false
}
for _, i := range ips {
if i.String() == ip.String() {
return true
}
}
return true
return false
}
29 changes: 27 additions & 2 deletions pkg/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (

var NetResolver *net.Resolver = net.DefaultResolver

var Zone string // Zone is the domain name of the cluster

func ParseStringToIPNet(s string) (ipnet *net.IPNet, err error) {
_, ipnet, err = net.ParseCIDR(s)
return
Expand Down Expand Up @@ -55,6 +57,29 @@ func ARecord(domain string) (ips []net.IP, err error) {
return
}

func IPtoPodHostName(ip string, zone string) string {
return fmt.Sprintf("%s.default.pod.%s", strings.ReplaceAll(ip, ".", "-"), zone)
func IPtoPodHostName(ip, namespace string) string {
return fmt.Sprintf("%s.%s.pod.%s", strings.ReplaceAll(ip, ".", "-"), namespace, Zone)
}

func TestPodVerified() bool {
iplist := []string{
"8.8.8.8",
"1.1.1.1",
"114.114.114.114",
}
for _, ip := range iplist {
targetHostName := IPtoPodHostName(ip, "kube-system")
log.Tracef("test if record %v is ip: %v", targetHostName, ip)
ips, err := ARecord(targetHostName)
if err != nil {
continue
}
// all of this ip should not return correct ip if verified is set.
for _, i := range ips {
if i.String() == ip {
return false
}
}
}
return true
}

0 comments on commit 8a2a14a

Please sign in to comment.