coverage.html 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  5. <title>kyoketsu: Go Coverage Report</title>
  6. <style>
  7. body {
  8. background: black;
  9. color: rgb(80, 80, 80);
  10. }
  11. body, pre, #legend span {
  12. font-family: Menlo, monospace;
  13. font-weight: bold;
  14. }
  15. #topbar {
  16. background: black;
  17. position: fixed;
  18. top: 0; left: 0; right: 0;
  19. height: 42px;
  20. border-bottom: 1px solid rgb(80, 80, 80);
  21. }
  22. #content {
  23. margin-top: 50px;
  24. }
  25. #nav, #legend {
  26. float: left;
  27. margin-left: 10px;
  28. }
  29. #legend {
  30. margin-top: 12px;
  31. }
  32. #nav {
  33. margin-top: 10px;
  34. }
  35. #legend span {
  36. margin: 0 5px;
  37. }
  38. .cov0 { color: rgb(192, 0, 0) }
  39. .cov1 { color: rgb(128, 128, 128) }
  40. .cov2 { color: rgb(116, 140, 131) }
  41. .cov3 { color: rgb(104, 152, 134) }
  42. .cov4 { color: rgb(92, 164, 137) }
  43. .cov5 { color: rgb(80, 176, 140) }
  44. .cov6 { color: rgb(68, 188, 143) }
  45. .cov7 { color: rgb(56, 200, 146) }
  46. .cov8 { color: rgb(44, 212, 149) }
  47. .cov9 { color: rgb(32, 224, 152) }
  48. .cov10 { color: rgb(20, 236, 155) }
  49. </style>
  50. </head>
  51. <body>
  52. <div id="topbar">
  53. <div id="nav">
  54. <select id="files">
  55. <option value="file0">git.aetherial.dev/aeth/kyoketsu/cmd/kyoketsu/kyoketsu.go (0.0%)</option>
  56. <option value="file1">git.aetherial.dev/aeth/kyoketsu/pkg/local.go (86.7%)</option>
  57. <option value="file2">git.aetherial.dev/aeth/kyoketsu/pkg/scanner.go (95.0%)</option>
  58. <option value="file3">git.aetherial.dev/aeth/kyoketsu/pkg/storage.go (0.0%)</option>
  59. </select>
  60. </div>
  61. <div id="legend">
  62. <span>not tracked</span>
  63. <span class="cov0">not covered</span>
  64. <span class="cov8">covered</span>
  65. </div>
  66. </div>
  67. <div id="content">
  68. <pre class="file" id="file0" style="display: none">/*
  69. GNU GENERAL PUBLIC LICENSE
  70. Version 3, 29 June 2007
  71. kyoketsu, a Client-To-Client Network Enumeration System
  72. Copyright (C) 2024 Russell Hrubesky, ChiralWorks Software LLC
  73. Copyright (C) 2007 Free Software Foundation, Inc. &lt;https://fsf.org/&gt;
  74. Everyone is permitted to copy and distribute verbatim copies
  75. of this license document, but changing it is not allowed.
  76. This program is free software: you can redistribute it and/or modify
  77. it under the terms of the GNU General Public License as published by
  78. the Free Software Foundation, either version 3 of the License,
  79. or (at your option) any later version.
  80. This program is distributed in the hope that it will be useful,
  81. but WITHOUT ANY WARRANTY; without even the implied warranty of
  82. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  83. See the GNU General Public License for more details.
  84. You should have received a copy of the GNU General Public License
  85. along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.
  86. */
  87. package main
  88. import (
  89. "flag"
  90. "fmt"
  91. "log"
  92. "net"
  93. "os"
  94. "strings"
  95. "sync"
  96. kyoketsu "git.aetherial.dev/aeth/kyoketsu/pkg"
  97. )
  98. var licenseMsg = "\n http-wokou Copyright (C) 2024 Russell Hrubesky, ChiralWorks Software LLC\n This program comes with ABSOLUTELY NO WARRANTY; for details type `http-wokou --license`\n This is free software, and you are welcome to redistribute it\n under certain conditions; type `http-wokou --redist` for details.\n\n"
  99. var redistMsg = "\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n"
  100. var licenseMsgLong = "\n GNU GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n Copyright (C) 2007 Free Software Foundation, Inc. &lt;https://fsf.org/&gt;\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n http-wokou, An HTTP Proxying framework for bypassing DNS Security\n Copyright (C) 2024 Russell Hrubesky, ChiralWorks Software LLC\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU General Public License for more details.\n\n You should have received a copy of the GNU General Public License\n along with this program. If not, see &lt;https://www.gnu.org/licenses/&gt;.\n\n"
  101. func main() <span class="cov0" title="0">{
  102. ip := flag.String("ips", "", "single ip address with CIDR notation to gather info about")
  103. licenseInfo := flag.Bool("license", false, "Pass this flag to display license and warantee information.")
  104. redistInfo := flag.Bool("redist", false, "Pass this flag to display redistribution information.")
  105. flag.Parse()
  106. if *licenseInfo </span><span class="cov0" title="0">{
  107. fmt.Println(licenseMsgLong)
  108. os.Exit(0)
  109. }</span>
  110. <span class="cov0" title="0">if *redistInfo </span><span class="cov0" title="0">{
  111. fmt.Println(redistMsg)
  112. os.Exit(0)
  113. }</span>
  114. <span class="cov0" title="0">fmt.Println(licenseMsg)
  115. var err error
  116. var addr *kyoketsu.IpSubnetMapper
  117. addr, err = kyoketsu.GetNetworkAddresses(*ip)
  118. if err != nil </span><span class="cov0" title="0">{
  119. log.Fatal(err)
  120. }</span>
  121. <span class="cov0" title="0">var wg sync.WaitGroup
  122. for i := range addr.Ipv4s </span><span class="cov0" title="0">{
  123. wg.Add(1)
  124. go func(target string, wg *sync.WaitGroup) </span><span class="cov0" title="0">{
  125. defer wg.Done()
  126. out := kyoketsu.PortWalk(target, kyoketsu.RetrieveScanDirectives().Pairs)
  127. if len(out.ListeningPorts) &gt; 0 </span><span class="cov0" title="0">{
  128. dns, _ := net.LookupAddr(out.IpAddress)
  129. out.Fqdn = strings.Join(dns, ", ")
  130. fmt.Printf("%+v\n", out)
  131. }</span>
  132. }(addr.Ipv4s[i].String(), &amp;wg)
  133. }
  134. <span class="cov0" title="0">wg.Wait()</span>
  135. }
  136. </pre>
  137. <pre class="file" id="file1" style="display: none">/*
  138. GNU GENERAL PUBLIC LICENSE
  139. Version 3, 29 June 2007
  140. kyoketsu, a Client-To-Client Network Enumeration System
  141. Copyright (C) 2024 Russell Hrubesky, ChiralWorks Software LLC
  142. Copyright (C) 2007 Free Software Foundation, Inc. &lt;https://fsf.org/&gt;
  143. Everyone is permitted to copy and distribute verbatim copies
  144. of this license document, but changing it is not allowed.
  145. This program is free software: you can redistribute it and/or modify
  146. it under the terms of the GNU General Public License as published by
  147. the Free Software Foundation, either version 3 of the License,
  148. or (at your option) any later version.
  149. This program is distributed in the hope that it will be useful,
  150. but WITHOUT ANY WARRANTY; without even the implied warranty of
  151. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  152. See the GNU General Public License for more details.
  153. You should have received a copy of the GNU General Public License
  154. along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.
  155. */
  156. package kyoketsu
  157. import (
  158. "fmt"
  159. "log"
  160. "net"
  161. "net/netip"
  162. "strconv"
  163. "strings"
  164. )
  165. type NetworkInterfaceNotFound struct{ Passed string }
  166. // Implementing error interface
  167. func (n *NetworkInterfaceNotFound) Error() string <span class="cov0" title="0">{
  168. return fmt.Sprintf("Interface: '%s' not found.", n.Passed)
  169. }</span>
  170. type IpSubnetMapper struct {
  171. Ipv4s []net.IP `json:"addresses"`
  172. NetworkAddr net.IP
  173. Current net.IP
  174. Mask int
  175. }
  176. /*
  177. Get the next IPv4 address of the address specified in the 'addr' argument,
  178. :param addr: the address to get the next address of
  179. */
  180. func getNextAddr(addr string) string <span class="cov8" title="1">{
  181. parsed, err := netip.ParseAddr(addr)
  182. if err != nil </span><span class="cov0" title="0">{
  183. log.Fatal("failed while parsing address in getNextAddr() ", err, "\n")
  184. }</span>
  185. <span class="cov8" title="1">return parsed.Next().String()</span>
  186. }
  187. /*
  188. get the network address of the ip address in 'addr' with the subnet mask from 'cidr'
  189. :param addr: the ipv4 address to get the network address of
  190. :param cidr: the CIDR notation of the subbet
  191. */
  192. func getNetwork(addr string, cidr int) string <span class="cov8" title="1">{
  193. addr = fmt.Sprintf("%s/%v", addr, cidr)
  194. ip, net, err := net.ParseCIDR(addr)
  195. if err != nil </span><span class="cov0" title="0">{
  196. log.Fatal("failed whilst attempting to parse cidr in getNetwork() ", err, "\n")
  197. }</span>
  198. <span class="cov8" title="1">return ip.Mask(net.Mask).String()</span>
  199. }
  200. /*
  201. Recursive function to get all of the IPv4 addresses for each IPv4 network that the host is on
  202. :param ipmap: a pointer to an IpSubnetMapper struct which contains domain details such as
  203. the subnet mask, the original network mask, and the current IP address used in the
  204. recursive function
  205. :param max: This is safety feature to prevent stack overflows, so you can manually set the depth to
  206. call the function
  207. */
  208. func addressRecurse(ipmap *IpSubnetMapper) <span class="cov8" title="1">{
  209. next := getNextAddr(ipmap.Current.String())
  210. nextNet := getNetwork(next, ipmap.Mask)
  211. currentNet := ipmap.NetworkAddr.String()
  212. if nextNet != currentNet </span><span class="cov8" title="1">{
  213. return
  214. }</span>
  215. <span class="cov8" title="1">ipmap.Current = net.ParseIP(next)
  216. ipmap.Ipv4s = append(ipmap.Ipv4s, net.ParseIP(next))
  217. addressRecurse(ipmap)</span>
  218. }
  219. /*
  220. Get all of the IPv4 addresses in the network that 'addr' belongs to. YOU MUST PASS THE ADDRESS WITH CIDR NOTATION
  221. i.e. '192.168.50.1/24'
  222. :param addr: the ipv4 address to use for subnet discovery
  223. */
  224. func GetNetworkAddresses(addr string) (*IpSubnetMapper, error) <span class="cov8" title="1">{
  225. ipmap := &amp;IpSubnetMapper{Ipv4s: []net.IP{}}
  226. ip, net, err := net.ParseCIDR(addr)
  227. if err != nil </span><span class="cov8" title="1">{
  228. return nil, err
  229. }</span>
  230. <span class="cov8" title="1">mask, err := strconv.Atoi(strings.Split(addr, "/")[1])
  231. if err != nil </span><span class="cov0" title="0">{
  232. return nil, err
  233. }</span>
  234. <span class="cov8" title="1">ipmap.NetworkAddr = ip.Mask(net.Mask)
  235. ipmap.Mask = mask
  236. ipmap.Current = ip.Mask(net.Mask)
  237. addressRecurse(ipmap)
  238. return ipmap, nil</span>
  239. }
  240. </pre>
  241. <pre class="file" id="file2" style="display: none">/*
  242. GNU GENERAL PUBLIC LICENSE
  243. Version 3, 29 June 2007
  244. kyoketsu, a Client-To-Client Network Enumeration System
  245. Copyright (C) 2024 Russell Hrubesky, ChiralWorks Software LLC
  246. Copyright (C) 2007 Free Software Foundation, Inc. &lt;https://fsf.org/&gt;
  247. Everyone is permitted to copy and distribute verbatim copies
  248. of this license document, but changing it is not allowed.
  249. This program is free software: you can redistribute it and/or modify
  250. it under the terms of the GNU General Public License as published by
  251. the Free Software Foundation, either version 3 of the License,
  252. or (at your option) any later version.
  253. This program is distributed in the hope that it will be useful,
  254. but WITHOUT ANY WARRANTY; without even the implied warranty of
  255. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  256. See the GNU General Public License for more details.
  257. You should have received a copy of the GNU General Public License
  258. along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.
  259. */
  260. package kyoketsu
  261. import (
  262. "fmt"
  263. "net"
  264. "sync"
  265. "time"
  266. )
  267. var PORT_MAP = map[int]string{
  268. 22: "ssh", 23: "telnet", 53: "dns", 80: "http", 25: "smtp", 443: "https", 8080: "unknown", 8081: "unknown",
  269. //8082: "unknown", 8085: "unknown", 8090: "unknown", 8091: "unknown", 9010: "unknown", 9012: "unknown", 10000: "unknown", 1433: "microsoft_sql",
  270. 3306: "mysql", 3050: "firebird", 5432: "postgres", 27017: "mongo", 6379: "redis", 8005: "tomcat", 6443: "kubernetes", 853: "dns-tls", 143: "imap",
  271. 389: "ldap", 445: "smb", 543: "kerberos", 544: "kerberos", 749: "kerberos", 760: "kerberos",
  272. }
  273. /*
  274. Need to work with with a database schema in mind, and revolve functionality around that
  275. */
  276. type Host struct {
  277. Fqdn string // The FQDN of the address targeted as per the systems default resolver
  278. IpAddress string // the IPv4 address (no ipv6 support yet)
  279. PingResponse bool // boolean value representing if the host responded to ICMP
  280. ListeningPorts map[int]string // list of maps depicting a port number -&gt; service name
  281. }
  282. /*
  283. Perform a concurrent TCP port dial on a host, either by domain name or IP.
  284. :param addr: the address of fqdn to scan
  285. :param portmap: a key/value pair of port numbers to service names to dial the host with
  286. */
  287. func PortWalk(addr string, portmap map[int]string) *Host <span class="cov8" title="1">{
  288. wg := &amp;sync.WaitGroup{}
  289. out := []*PortScanResult{}
  290. for p, s := range portmap </span><span class="cov8" title="1">{
  291. wg.Add(1)
  292. go func(target string, p int, s string) </span><span class="cov8" title="1">{
  293. defer wg.Done()
  294. out = append(out, singlePortScan(target, p, s))
  295. }</span>(addr, p, s)
  296. }
  297. <span class="cov8" title="1">wg.Wait()
  298. host := &amp;Host{IpAddress: addr, ListeningPorts: map[int]string{}}
  299. for i := range out </span><span class="cov8" title="1">{
  300. if out[i].Listening </span><span class="cov8" title="1">{
  301. host.ListeningPorts[out[i].PortNumber] = out[i].Service
  302. }</span>
  303. }
  304. <span class="cov8" title="1">return host</span>
  305. }
  306. type PortScanResult struct {
  307. // This is used to represent the results of a port scan against one host
  308. PortNumber int `json:"port_number"` // The port number that was scanned
  309. Service string `json:"service"` // the name of the service that the port was identified/mapped to
  310. Protocol string `json:"protocol"` // The IP protocol (TCP/UDP)
  311. Listening bool `json:"listening"` // A boolean value that depicts if the service is listening or not
  312. }
  313. type PortScanDirective struct {
  314. // Struct for dependency injecting the dynamic port map used for scans
  315. Pairs map[int]string
  316. }
  317. /*
  318. Wrapper function to dependency inject the resource for a port -&gt; service name mapping.
  319. May move to a database, or something.
  320. */
  321. func RetrieveScanDirectives() PortScanDirective <span class="cov0" title="0">{
  322. return PortScanDirective{Pairs: PORT_MAP}
  323. }</span>
  324. /*
  325. Scans a single host on a single port
  326. :param addr: the address to dial
  327. :param port: the port number to dial
  328. :param svcs: the name of the service that the port is associate with
  329. */
  330. func singlePortScan(addr string, port int, svcs string) *PortScanResult <span class="cov8" title="1">{
  331. address := fmt.Sprintf("%v:%d", addr, port)
  332. conn, err := net.DialTimeout("tcp", address, 5*time.Second)
  333. if err != nil </span><span class="cov8" title="1">{
  334. return &amp;PortScanResult{PortNumber: port, Protocol: "tcp", Service: svcs, Listening: false}
  335. }</span>
  336. <span class="cov8" title="1">conn.Close()
  337. return &amp;PortScanResult{PortNumber: port, Protocol: "tcp", Service: svcs, Listening: true}</span>
  338. }
  339. </pre>
  340. <pre class="file" id="file3" style="display: none">/*
  341. GNU GENERAL PUBLIC LICENSE
  342. Version 3, 29 June 2007
  343. kyoketsu, a Client-To-Client Network Enumeration System
  344. Copyright (C) 2024 Russell Hrubesky, ChiralWorks Software LLC
  345. Copyright (C) 2007 Free Software Foundation, Inc. &lt;https://fsf.org/&gt;
  346. Everyone is permitted to copy and distribute verbatim copies
  347. of this license document, but changing it is not allowed.
  348. This program is free software: you can redistribute it and/or modify
  349. it under the terms of the GNU General Public License as published by
  350. the Free Software Foundation, either version 3 of the License,
  351. or (at your option) any later version.
  352. This program is distributed in the hope that it will be useful,
  353. but WITHOUT ANY WARRANTY; without even the implied warranty of
  354. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  355. See the GNU General Public License for more details.
  356. You should have received a copy of the GNU General Public License
  357. along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.
  358. */
  359. package kyoketsu
  360. import (
  361. "context"
  362. "fmt"
  363. "time"
  364. "go.mongodb.org/mongo-driver/mongo"
  365. "go.mongodb.org/mongo-driver/mongo/options"
  366. )
  367. type TopologyDatabaseIO interface {
  368. /*
  369. This interface defines the Input and output methods that will be necessary
  370. for an appropriate implementation of the data storage that the distributed system will use.
  371. When I get around to implementing the client-to-client format of this, it could be anything.
  372. */
  373. AddHostToDb(*Host) error // Add a host to the hosts table
  374. UpdateHostEntry(string, *Host) error //Update a host entry, indexing by its ip address
  375. RemoveHostEntry(string) error // Remove a host from the database
  376. }
  377. type MongoClient struct {
  378. conn *mongo.Client
  379. }
  380. func NewMongoClient(host string, port int) *MongoClient <span class="cov0" title="0">{
  381. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  382. defer cancel()
  383. client, err := mongo.Connect(ctx, options.Client().ApplyURI(fmt.Sprintf("mongodb://%s:%v", host, port)))
  384. defer func() </span><span class="cov0" title="0">{
  385. if err = client.Disconnect(ctx); err != nil </span><span class="cov0" title="0">{
  386. panic(err)</span>
  387. }
  388. }()
  389. <span class="cov0" title="0">return &amp;MongoClient{conn: client}</span>
  390. }
  391. func (m *MongoClient) addDocument(id string, data interface{}) error <span class="cov0" title="0">{
  392. return nil
  393. }</span>
  394. func (m *MongoClient) AddHostToDb(host *Host) error <span class="cov0" title="0">{
  395. return nil
  396. }</span>
  397. func (m *MongoClient) UpdateHostEntry(id string, host *Host) error <span class="cov0" title="0">{
  398. return nil
  399. }</span>
  400. func (m *MongoClient) RemoveHostEntry(id string) error <span class="cov0" title="0">{
  401. return nil
  402. }</span>
  403. </pre>
  404. </div>
  405. </body>
  406. <script>
  407. (function() {
  408. var files = document.getElementById('files');
  409. var visible;
  410. files.addEventListener('change', onChange, false);
  411. function select(part) {
  412. if (visible)
  413. visible.style.display = 'none';
  414. visible = document.getElementById(part);
  415. if (!visible)
  416. return;
  417. files.value = part;
  418. visible.style.display = 'block';
  419. location.hash = part;
  420. }
  421. function onChange() {
  422. select(files.value);
  423. window.scrollTo(0, 0);
  424. }
  425. if (location.hash != "") {
  426. select(location.hash.substr(1));
  427. }
  428. if (!visible) {
  429. select("file0");
  430. }
  431. })();
  432. </script>
  433. </html>