local.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /*
  2. GNU GENERAL PUBLIC LICENSE
  3. Version 3, 29 June 2007
  4. kyoketsu, a Client-To-Client Network Enumeration System
  5. Copyright (C) 2024 Russell Hrubesky, ChiralWorks Software LLC
  6. Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
  7. Everyone is permitted to copy and distribute verbatim copies
  8. of this license document, but changing it is not allowed.
  9. This program is free software: you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License as published by
  11. the Free Software Foundation, either version 3 of the License,
  12. or (at your option) any later version.
  13. This program is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  16. See the GNU General Public License for more details.
  17. You should have received a copy of the GNU General Public License
  18. along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. package kyoketsu
  21. import (
  22. "fmt"
  23. "log"
  24. "math"
  25. "net"
  26. "net/netip"
  27. "strconv"
  28. "strings"
  29. "github.com/fatih/color"
  30. "github.com/manifoldco/promptui"
  31. )
  32. const IPV4_BITLEN = 32
  33. type NetworkInterfaceNotFound struct{ Passed string }
  34. // Implementing error interface
  35. func (n *NetworkInterfaceNotFound) Error() string {
  36. return fmt.Sprintf("Interface: '%s' not found.", n.Passed)
  37. }
  38. type IpSubnetMapper struct {
  39. Ipv4s []net.IP `json:"addresses"`
  40. NetworkAddr net.IP
  41. Current net.IP
  42. Mask int
  43. }
  44. type PromptEntry struct {
  45. HostAddress string
  46. NetworkAddress string
  47. Cidr string
  48. SubnetMask string
  49. InterfaceName string
  50. MacAddress string
  51. }
  52. type TuiSelectionFeed struct {
  53. Choice []PromptEntry
  54. }
  55. /*
  56. Get the next IPv4 address of the address specified in the 'addr' argument,
  57. :param addr: the address to get the next address of
  58. */
  59. func getNextAddr(addr string) string {
  60. parsed, err := netip.ParseAddr(addr)
  61. if err != nil {
  62. log.Fatal("failed while parsing address in getNextAddr() ", err, "\n")
  63. }
  64. return parsed.Next().String()
  65. }
  66. /*
  67. get the network address of the ip address in 'addr' with the subnet mask from 'cidr'
  68. :param addr: the ipv4 address to get the network address of
  69. :param cidr: the CIDR notation of the subbet
  70. */
  71. func getNetwork(addr string, cidr int) string {
  72. addr = fmt.Sprintf("%s/%v", addr, cidr)
  73. ip, net, err := net.ParseCIDR(addr)
  74. if err != nil {
  75. log.Fatal("failed whilst attempting to parse cidr in getNetwork() ", err, "\n")
  76. }
  77. return ip.Mask(net.Mask).String()
  78. }
  79. /*
  80. Recursive function to get all of the IPv4 addresses for each IPv4 network that the host is on
  81. :param ipmap: a pointer to an IpSubnetMapper struct which contains domain details such as
  82. the subnet mask, the original network mask, and the current IP address used in the
  83. recursive function
  84. :param max: This is safety feature to prevent stack overflows, so you can manually set the depth to
  85. call the function
  86. */
  87. func addressRecurse(ipmap IpSubnetMapper) IpSubnetMapper {
  88. next := getNextAddr(ipmap.Ipv4s[len(ipmap.Ipv4s)-1].String())
  89. if getNetwork(next, ipmap.Mask) != ipmap.NetworkAddr.String() {
  90. return ipmap
  91. }
  92. ipmap.Ipv4s = append(ipmap.Ipv4s, net.ParseIP(next))
  93. return addressRecurse(ipmap)
  94. }
  95. /*
  96. Get all of the IPv4 addresses in the network that 'addr' belongs to. YOU MUST PASS THE ADDRESS WITH CIDR NOTATION
  97. i.e. '192.168.50.1/24'
  98. :param addr: the ipv4 address to use for subnet discovery
  99. */
  100. func GetNetworkAddresses(addr string) (IpSubnetMapper, error) {
  101. ip, ntwrk, err := net.ParseCIDR(addr)
  102. if err != nil {
  103. return IpSubnetMapper{}, err
  104. }
  105. mask, err := strconv.Atoi(strings.Split(addr, "/")[1])
  106. if err != nil {
  107. return IpSubnetMapper{}, err
  108. }
  109. ipmap := IpSubnetMapper{Ipv4s: []net.IP{ip},
  110. NetworkAddr: ip.Mask(ntwrk.Mask),
  111. Mask: mask,
  112. Current: ip.Mask(ntwrk.Mask)}
  113. return addressRecurse(ipmap), nil
  114. }
  115. /*
  116. Turns a set of network mask bits into a valid IPv4 representation
  117. :param ones: number of 1's in the netmask, i.e. 16 == 11111111 11111111 00000000 00000000
  118. :param bits: the number of bits that the mask consists of (need to keep this param for ipv6 support later)
  119. */
  120. func bitsToMask(ones int, bits int) string {
  121. var bitmask []int
  122. for i := 0; i < ones; i++ {
  123. bitmask = append(bitmask, 1)
  124. }
  125. for i := ones; i < bits; i++ {
  126. bitmask = append(bitmask, 0)
  127. }
  128. octets := []string{
  129. strconv.Itoa(base2to10(bitmask[0:8])),
  130. strconv.Itoa(base2to10(bitmask[8:16])),
  131. strconv.Itoa(base2to10(bitmask[16:24])),
  132. strconv.Itoa(base2to10(bitmask[24:32])),
  133. }
  134. return strings.Join(octets, ".")
  135. }
  136. /*
  137. convert a base 2 number (represented as an array) to a base 10 integer
  138. :param bits: the slice of ints split into an array, e.g. '11110000' would be [1 1 1 1 0 0 0 0]
  139. */
  140. func base2to10(bits []int) int {
  141. var sum int
  142. sum = 0
  143. for i := range bits {
  144. bits[i] = bits[i] * powerInt(2, len(bits)-1-i)
  145. }
  146. for i := range bits {
  147. sum = sum + bits[i]
  148. }
  149. return sum
  150. }
  151. /*
  152. Wrapper func for getting the value of x to the power of y, as int opposed to float64
  153. :param x: the base number to operate on
  154. :param y: the exponent
  155. */
  156. func powerInt(x int, y int) int {
  157. return int(math.Pow(float64(x), float64(y)))
  158. }
  159. // Needs cleanup, but this function populatest a data structure that will be used during TUI program startup
  160. func RetrieveLocalAddresses() (TuiSelectionFeed, error) {
  161. var tuidata TuiSelectionFeed
  162. intf, err := net.Interfaces()
  163. if err != nil {
  164. return tuidata, err
  165. }
  166. addrs, err := net.InterfaceAddrs()
  167. if err != nil {
  168. return tuidata, err
  169. }
  170. for x := range addrs {
  171. var mac string
  172. var interfacename string
  173. ip, net, err := net.ParseCIDR(addrs[x].String())
  174. if err != nil {
  175. return tuidata, err
  176. }
  177. for i := range intf {
  178. intfAddrs, err := intf[i].Addrs()
  179. if err != nil {
  180. return tuidata, err
  181. }
  182. for y := range intfAddrs {
  183. if strings.Contains(intfAddrs[y].String(), strings.Split(ip.String(), "/")[0]) {
  184. interfacename = intf[i].Name
  185. mac = intf[i].HardwareAddr.String()
  186. }
  187. }
  188. }
  189. tuidata.Choice = append(tuidata.Choice, PromptEntry{
  190. HostAddress: ip.String(),
  191. NetworkAddress: ip.Mask(net.Mask).String(),
  192. Cidr: strings.Split(addrs[x].String(), "/")[1],
  193. SubnetMask: bitsToMask(net.Mask.Size()),
  194. MacAddress: mac,
  195. InterfaceName: interfacename,
  196. })
  197. }
  198. return tuidata, nil
  199. }
  200. // This is a helper function to return the TUI template for interactive mode
  201. func TuiTemplate() *promptui.SelectTemplates {
  202. green := color.New(color.FgGreen).Add(color.Bold)
  203. templ := &promptui.SelectTemplates{
  204. Label: "{{ . }}",
  205. Active: green.Sprint(" Network Address: {{ .NetworkAddress }}"),
  206. Inactive: " {{ .NetworkAddress}}",
  207. Selected: green.Sprint(" {{ .NetworkAddress }}"),
  208. Details: `
  209. {{ "Network Address: " | green | bold }} {{ .NetworkAddress }}
  210. {{ "Interface Name: " | green | bold }} {{ .InterfaceName }}
  211. {{ "Mac Address: " | green | bold }} {{ .MacAddress }}
  212. {{ "Subnet Mask: " | green | bold }} {{ .SubnetMask }}
  213. {{ "CIDR Notation: " | green | bold }} /{{ .Cidr }}`,
  214. }
  215. return templ
  216. }