aeth 7 сар өмнө
parent
commit
e22f505284

+ 4 - 0
Makefile

@@ -33,6 +33,10 @@ build:
 	go build -x -v -o ./build/linux/$(KYOKETSU)/$(KYOKETSU) ./cmd/$(KYOKETSU)/$(KYOKETSU).go && \
 	go build -x -v -o ./build/linux/$(KYOKETSU_WEB)/$(KYOKETSU_WEB) ./cmd/$(KYOKETSU_WEB)/$(KYOKETSU_WEB).go
 
+build-arm:
+	export GOOS=linux && export GOARCH=arm && go build -x -v -o ./build/linux/amd/$(KYOKETSU)/$(KYOKETSU) ./cmd/$(KYOKETSU)/$(KYOKETSU).go
+
+
 format:
 	go fmt ./...
 

+ 5 - 0
go.mod

@@ -3,11 +3,14 @@ module git.aetherial.dev/aeth/kyoketsu
 go 1.21.1
 
 require (
+	github.com/asavie/xdp v0.3.3 // indirect
 	github.com/chzyer/readline v1.5.1 // indirect
+	github.com/cilium/ebpf v0.4.0 // indirect
 	github.com/fatih/color v1.16.0 // indirect
 	github.com/go-ping/ping v1.1.0 // indirect
 	github.com/golang/snappy v0.0.1 // indirect
 	github.com/google/go-cmp v0.6.0 // indirect
+	github.com/google/gopacket v1.1.19 // indirect
 	github.com/google/pprof v0.0.0-20240416155748-26353dc0451f // indirect
 	github.com/google/uuid v1.2.0 // indirect
 	github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465 // indirect
@@ -17,6 +20,8 @@ require (
 	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/mattn/go-sqlite3 v1.14.22 // indirect
 	github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
+	github.com/vishvananda/netlink v1.1.0 // indirect
+	github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect
 	github.com/xdg-go/pbkdf2 v1.0.0 // indirect
 	github.com/xdg-go/scram v1.1.2 // indirect
 	github.com/xdg-go/stringprep v1.0.4 // indirect

+ 30 - 0
go.sum

@@ -1,3 +1,5 @@
+github.com/asavie/xdp v0.3.3 h1:b5Aa3EkMJYBeUO5TxPTIAa4wyUqYcsQr2s8f6YLJXhE=
+github.com/asavie/xdp v0.3.3/go.mod h1:Vv5p+3mZiDh7ImdSvdon3E78wXyre7df5V58ATdIYAY=
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
@@ -6,14 +8,20 @@ github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI
 github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
+github.com/cilium/ebpf v0.4.0 h1:QlHdikaxALkqWasW8hAC1mfR0jdmvbfaBdBPFmRSglA=
+github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
 github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
 github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
+github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
 github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw=
 github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
 github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
+github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
 github.com/google/pprof v0.0.0-20240416155748-26353dc0451f h1:WpZiq8iqvGjJ3m3wzAVKL6+0vz7VkE79iSy9GII00II=
 github.com/google/pprof v0.0.0-20240416155748-26353dc0451f/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
 github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
@@ -22,6 +30,9 @@ github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465 h1:KwWnWVW
 github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
 github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
 github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+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/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
 github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
 github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
@@ -31,8 +42,13 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
 github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
+github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
 github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
 github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
+github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
+github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
+github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
+github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
 github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
 github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
 github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
@@ -45,13 +61,18 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t
 go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
 go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
 golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
 golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
 golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -64,8 +85,13 @@ golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -84,5 +110,9 @@ golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 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=

+ 11 - 0
pkg/html/templates/home.html

@@ -34,6 +34,16 @@
                               <button type="submit">filter</button>
                         </form>
                     </div>
+                    <div class="col-2">
+                        <a style="color: white; font-family: monospace;">Exclude FQDN pattern:</a>
+                        <form method="post"
+                              hx-target="#response-div"
+                              hx-post="/excludefqdn"
+                              hx-ext="json-enc">
+                              <input type="text" name="fqdn_pattern" placeholder="wasted-domain.xyz" required>
+                              <button type="submit">filter</button>
+                        </form>
+                    </div>
                 </div>
             </div>
         </div>
@@ -42,6 +52,7 @@
             <thead>
                 <tr>
                     <th scope="col"><p style="font-family: monospace;">FQDN</p></th>
+                    <th scope="col"><p style="font-family: monospace;">Link</p></th>
                     <th scope="col"><p style="font-family: monospace;">IPv4 Address</p></th>
                     <th scope="col"><p style="font-family: monospace;">IPv4 Network</p></th>
                     <th scope="col"><p style="font-family: monospace;">Ping Response?</p></th>

+ 1 - 0
pkg/html/templates/ip_table.html

@@ -1,6 +1,7 @@
 {{ define "ip_table.html" }}
 <tr>
 <th scope="row"><p style="font-family: monospace;">{{ .Fqdn }}</p></th>
+<td><a href="{{ .FormatUrl }}" style="font-family: monospace;"> {{ .FormatUrl }}</a></td>
         <td><p style="font-family: monospace;">{{ .IpAddress }}</p></td>
         <td><p style="font-family: monospace;">{{ .Network }}</p></td>
         <td><p style="font-family: monospace;">{{ .PingResponse }}</p></td>

+ 104 - 0
pkg/packet.go

@@ -0,0 +1,104 @@
+package kyoketsu
+
+import (
+	"fmt"
+	"net"
+
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+)
+
+// PacketOption is a function that applies a configuration to a PacketConfig.
+type PacketOption func(*PacketConfig) error
+
+// PacketConfig stores configuration for building a packet.
+type PacketConfig struct {
+	SrcIP, DstIP     net.IP
+	SrcPort, DstPort layers.TCPPort
+	SrcMAC, DstMAC   net.HardwareAddr
+	PayloadSize      int
+}
+
+func buildPayload(payloadSize int) []byte {
+	payload := make([]byte, payloadSize)
+	for i := range payload {
+		payload[i] = byte(i % 256) // Example payload; adjust as needed
+	}
+	return payload
+}
+
+// WithEthernetLayer enables the Ethernet layer in the packet.
+func WithEthernetLayer(srcMAC, dstMAC net.HardwareAddr) PacketOption {
+	return func(c *PacketConfig) error {
+		c.SrcMAC = srcMAC
+		c.DstMAC = dstMAC
+		return nil
+	}
+}
+
+// WithIpLayer enables the IP layer in the packet.
+func WithIpLayer(srcIp, dstIp net.IP) PacketOption {
+	return func(c *PacketConfig) error {
+		c.SrcIP = srcIp
+		c.DstIP = dstIp
+		return nil
+	}
+}
+
+// WithPayloadSize sets the payload size for the packet.
+func WithPayloadSize(size int) PacketOption {
+	return func(c *PacketConfig) error {
+		c.PayloadSize = size
+		return nil
+	}
+}
+
+// NewPacketConfig creates a new PacketConfig with specified options.
+func NewPacketConfig(opts ...PacketOption) (*PacketConfig, error) {
+	config := &PacketConfig{}
+
+	for _, opt := range opts {
+		if err := opt(config); err != nil {
+			return nil, err
+		}
+	}
+	return config, nil
+}
+
+// BuildPacket constructs the packet based on the PacketConfig.
+// It automatically includes the Ethernet layer if both SrcMAC and DstMAC are provided.
+func BuildPacket(c *PacketConfig) ([]byte, error) {
+	buf := gopacket.NewSerializeBuffer()
+	var layersToSerialize []gopacket.SerializableLayer
+
+	// Automatically include the Ethernet layer if MAC addresses are provided
+	if c.SrcMAC != nil && c.DstMAC != nil {
+		ethLayer := &layers.Ethernet{
+			SrcMAC:       c.SrcMAC,
+			DstMAC:       c.DstMAC,
+			EthernetType: layers.EthernetTypeIPv4,
+		}
+		layersToSerialize = append(layersToSerialize, ethLayer)
+	}
+
+	// Set IP layer
+	ipLayer := &layers.IPv4{
+		Version:  4,
+		TTL:      64,
+		SrcIP:    c.SrcIP,
+		DstIP:    c.DstIP,
+		Protocol: layers.IPProtocolTCP,
+	}
+	layersToSerialize = append(layersToSerialize, ipLayer)
+
+	payload := make([]byte, c.PayloadSize)
+	// Optionally, fill the payload with data
+	layersToSerialize = append(layersToSerialize, gopacket.Payload(payload))
+
+	// Serialize the packet layers into the buffer
+	if err := gopacket.SerializeLayers(buf, gopacket.SerializeOptions{ComputeChecksums: true, FixLengths: true}, layersToSerialize...); err != nil {
+		return nil, fmt.Errorf("error serializing packet: %w", err)
+	}
+
+	return buf.Bytes(), nil
+}

+ 58 - 22
pkg/scanner.go

@@ -34,6 +34,8 @@ import (
 	"time"
 )
 
+const NoFqdn = "Not found with default resolver"
+
 /*
 Need to work with with a database schema in mind, and revolve functionality around that
 */
@@ -48,6 +50,35 @@ type Host struct {
 	Id             int64
 }
 
+func (h Host) FormatUrl() string {
+	ports := strings.Split(h.PortString, ",")
+
+	var https bool
+	var http bool
+	var url string
+	for i := range ports {
+		if ports[i] == "443" {
+			https = true
+		}
+		if ports[i] == "80" {
+			http = true
+		}
+	}
+	if h.Fqdn == NoFqdn {
+		url = h.IpAddress
+	} else {
+		url = h.Fqdn
+	}
+	if https {
+		return "https://" + strings.Trim(url, ".")
+	}
+	if http {
+
+		return "http://" + strings.Trim(url, ".")
+	}
+	return "none"
+}
+
 /*
 Perform a concurrent TCP port dial on a host, either by domain name or IP.
 
@@ -80,7 +111,7 @@ May move to a database, or something.
 */
 func RetrieveScanDirectives() []int {
 
-	var portmap = []int{22, 80, 443, 8080, 4379, 445, 53, 153, 27017}
+	var portmap = []int{80, 443}
 	return portmap
 }
 
@@ -96,12 +127,9 @@ func singlePortScan(addr string, port int) int {
 	conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%d", addr, port), 2*time.Second)
 	if err != nil {
 		return 0
-		//	return PortScanResult{PortNumber: port, Protocol: "tcp", Listening: false}
 	}
-	fmt.Printf("Host %s responded.\n", addr)
 	conn.Close()
 	return port
-	//return PortScanResult{PortNumber: port, Protocol: "tcp", Listening: true}
 }
 
 /*
@@ -136,37 +164,45 @@ func NetSweep(ips []net.IP, cidr int, ports []int, scanned chan Host) {
 func getFqdn(ip string) string {
 	names, err := net.LookupAddr(ip)
 	if err != nil {
-		return "not found with default resolver"
+		return NoFqdn
 	}
 	return strings.Join(names, ", ")
 }
 
-/*
-Create a new TCP dialer to share in a goroutine
-*/
-func NewDialer() net.Dialer {
-	return net.Dialer{}
+func NewSocket() int {
+	fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, int(htons(syscall.ETH_P_IP)))
+	if err != nil {
+		log.Fatal("Could not create a new socket ", err)
+	}
+	return fd
 }
 
-/*
-Create a new low level networking interface socket
-:param intf: the name of the interface to bind the socket to
-*/
-func NewTCPSock(interfaceName string) *syscall.SockaddrLinklayer {
-	sock, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, syscall.ETH_P_IP)
+func BuildAndSend(intf string, fd int, srcMac net.HardwareAddr, dstMac net.HardwareAddr, srcIp net.IP, dstIp net.IP, srcPort int, dstPort int) {
+	ifi, err := net.InterfaceByName(intf)
 	if err != nil {
-		log.Fatal(err, " Could not create raw AF_PACKET socket.\n")
+		log.Fatal("Interface was not found on the host: ", err)
 	}
-	defer syscall.Close(sock)
-	intf, err := net.InterfaceByName(interfaceName)
+	config, err := NewPacketConfig(
+		WithEthernetLayer(srcMac, dstMac),
+		WithIpLayer(srcIp, dstIp),
+		WithPayloadSize(1024),
+	)
 	if err != nil {
-		log.Fatal(err, " Couldnt locate that interface. Are you sure you mean to pass ", interfaceName, " ?")
+		log.Fatal("error configuring packet: ", err)
 	}
-	return &syscall.SockaddrLinklayer{
+	addr := &syscall.SockaddrLinklayer{
 		Protocol: htons(syscall.ETH_P_IP),
-		Ifindex:  intf.Index,
+		Ifindex:  ifi.Index,
 	}
 
+	// build the packet
+	packet, err := BuildPacket(config)
+	if err != nil {
+		log.Fatal("failed to build packet: %w", err)
+	}
+	if err = syscall.Sendto(fd, packet, 0, addr); err != nil {
+		log.Fatal("Could not send packet out to target, ", err)
+	}
 }
 
 // htons converts a uint16 from host- to network byte order.

+ 32 - 0
pkg/storage.go

@@ -30,6 +30,7 @@ package kyoketsu
 import (
 	"database/sql"
 	"errors"
+	"strings"
 
 	"github.com/mattn/go-sqlite3"
 )
@@ -44,6 +45,7 @@ type TopologyDatabaseIO interface {
 	Create(host Host) (*Host, error)
 	All() ([]Host, error)
 	GetByNetwork(network string) ([]Host, error)
+	FilterDnsPattern(patterns []string) ([]Host, error)
 	GetByIP(ip string) (*Host, error)
 	Update(id int64, updated Host) (*Host, error)
 	Delete(id int64) error
@@ -201,3 +203,33 @@ func (r *SQLiteRepo) GetByNetwork(network string) ([]Host, error) {
 	}
 	return hosts, nil
 }
+
+func (r *SQLiteRepo) FilterDnsPattern(patterns []string) ([]Host, error) {
+	var queryBuilder strings.Builder
+	queryBuilder.WriteString("SELECT * FROM hosts WHERE ")
+	args := make([]interface{}, len(patterns))
+
+	for i, pattern := range patterns {
+		if i > 0 {
+			queryBuilder.WriteString(" AND ")
+		}
+		queryBuilder.WriteString("fqdn NOT LIKE ?")
+		args[i] = "%" + pattern + "%"
+	}
+
+	rows, err := r.db.Query(queryBuilder.String(), args...)
+	if err != nil {
+		return nil, err
+	}
+	var hosts []Host
+	defer rows.Close()
+
+	for rows.Next() {
+		var host Host
+		if err := rows.Scan(&host.Id, &host.Fqdn, &host.IpAddress, &host.PortString, &host.Network); err != nil {
+			return nil, err
+		}
+		hosts = append(hosts, host)
+	}
+	return hosts, nil
+}

+ 63 - 24
pkg/webserver.go

@@ -13,7 +13,8 @@ import (
 )
 
 type ScanRequest struct {
-	IpAddress string `json:"ip_address"`
+	IpAddress   string `json:"ip_address"`
+	FqdnPattern string `json:"fqdn_pattern"`
 }
 
 // Holding all static web server resources
@@ -41,6 +42,7 @@ func RunHttpServer(port int, dbhook TopologyDatabaseIO, portmap []int) {
 	http.Handle("/static/", assets)
 	http.Handle("/home", htmlHndl)
 	http.Handle("/subnets", htmlHndl)
+	http.Handle("/excludefqdn", htmlHndl)
 	http.Handle("/refresh", execHndl)
 
 	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%v", port), nil))
@@ -75,7 +77,12 @@ func (e *ExecutionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	go func(wr http.ResponseWriter, templ *template.Template) {
 		for x := range scanned {
 			if len(x.ListeningPorts) > 0 {
-				templ.Execute(wr, x)
+
+				err := templ.Execute(wr, x)
+				if err != nil {
+					fmt.Println(err, x)
+
+				}
 
 				host, err := e.DbHook.GetByIP(x.IpAddress)
 				if err != nil {
@@ -107,6 +114,55 @@ type HtmlHandler struct {
 	DbHook     TopologyDatabaseIO
 }
 
+func (h *HtmlHandler) subnetQueryHandler(w http.ResponseWriter, r *http.Request) {
+	var req ScanRequest
+	b, err := io.ReadAll(r.Body)
+	defer r.Body.Close()
+	if err != nil {
+		fmt.Fprintf(w, "There was an error reading the input: %s", err)
+		return
+	}
+	err = json.Unmarshal(b, &req)
+	if err != nil {
+		fmt.Fprintf(w, "There was an error reading the input: %s", err)
+		return
+	}
+	data, err := h.DbHook.GetByNetwork(req.IpAddress)
+	if err != nil {
+		fmt.Fprintf(w, "There was an error reading from the database: %s", err)
+		return
+	}
+	for _, host := range data {
+		h.TableEntry.Execute(w, host)
+	}
+
+}
+
+func (h *HtmlHandler) fqdnQueryHandler(w http.ResponseWriter, r *http.Request) {
+	var req ScanRequest
+	b, err := io.ReadAll(r.Body)
+	defer r.Body.Close()
+	if err != nil {
+		fmt.Fprintf(w, "There was an error reading the input: %s", err)
+		return
+	}
+	err = json.Unmarshal(b, &req)
+	if err != nil {
+		fmt.Fprintf(w, "There was an error reading the input: %s", err)
+		return
+	}
+	dnsList := strings.Split(req.FqdnPattern, ",")
+	data, err := h.DbHook.FilterDnsPattern(dnsList)
+	if err != nil {
+		fmt.Fprintf(w, "There was an error reading from the database: %s", err)
+		return
+	}
+	for _, host := range data {
+		h.TableEntry.Execute(w, host)
+	}
+
+}
+
 /*
 Handler function for HTML serving
 
@@ -127,28 +183,11 @@ func (h *HtmlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		w.Header().Add("Location", "/home")
 		return
 	}
-	if r.RequestURI == "/subnets" {
-		fmt.Println("request recv")
-		var req ScanRequest
-		b, err := io.ReadAll(r.Body)
-		defer r.Body.Close()
-		if err != nil {
-			fmt.Fprintf(w, "There was an error reading the input: %s", err)
-			return
-		}
-		err = json.Unmarshal(b, &req)
-		if err != nil {
-			fmt.Fprintf(w, "There was an error reading the input: %s", err)
-			return
-		}
-		data, err := h.DbHook.GetByNetwork(req.IpAddress)
-		if err != nil {
-			fmt.Fprintf(w, "There was an error reading from the database: %s", err)
-			return
-		}
-		for _, host := range data {
-			h.TableEntry.Execute(w, host)
-		}
+	switch r.RequestURI {
+	case "/subnets":
+		h.subnetQueryHandler(w, r)
+	case "/excludefqdn":
+		h.fqdnQueryHandler(w, r)
 	}
 }