package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
)

var clear map[string]func()

type NetModel struct {
	o1, o2, o3, o4, mask int
	sep string
	hosts int
}

func init() {
	clear = make(map[string]func())
	clear["linux"] = func() {
		cmd := exec.Command("clear")
		cmd.Stdout = os.Stdout
		_ = cmd.Run()
	}
	clear["windows"] = func() {
		cmd := exec.Command("cmd", "/c", "cls")
		cmd.Stdout = os.Stdout
		_ = cmd.Run()
	}
}

func printHeader() {
	fmt.Printf("-------[ IP AUTO CALC v0.1 ]------- \n\n")
}
func print4(t1, t2, t3, t4 int, word string) {
	fmt.Printf("[+] %s: %d.%d.%d.%d \n", word, t1, t2, t3, t4)
}
func printBin(t string, word string) {
	fmt.Printf("[+] %s: %s \n", word, t)
}
func printErr(text, code string) {
	fmt.Printf("[!] ERROR(%s): %s\n\n", code, text)
}
func printWrn(text string) {
	fmt.Printf("[-] INFO: %s\n", text)
}

func CallClear() {
	value, ok := clear[runtime.GOOS]
	if ok {
		value()
	} else {
		for i := 0; i < 20; i++ {
			fmt.Printf("\n\n\n\n\n\n\n")
		}
	}
	printHeader()
}

func getInterfaces() (string, int) {

	interfaces, err := net.Interfaces()
	if err != nil {
		panic(err)
	}
	CallClear()
	for _, intFace := range interfaces {

		adds, err := intFace.Addrs()
		if err != nil {
			panic(err)
		}

		for _, add := range adds {
			CallClear()
			if ip, ok := add.(*net.IPNet); ok {
				fmt.Print("IP: ", ip)
				var input string
				fmt.Print(". Get this? [y/n]: ")
				_, _ = fmt.Scanf("%s", &input)
				if input == "y" || input == "yes" {
					m, _ := ip.Mask.Size()

					return ip.IP.String(), m
				} else {
					printWrn("Search for others IP...")
				}
			}
		}
	}
	return "", 0
}

func getPublicIP() {
	resp, err := http.Get("https:
	if err != nil {
		log.Fatalln(err)
	}
	body, _ := ioutil.ReadAll(resp.Body)
	p := strings.Replace(string(body), "\n", "", 1)
	fmt.Printf("[+] PUBLIC IP: %s\n\n", p)
}

func getManualIP() (string, int) {
	address := os.Getenv("ADDRESS")
	mask, _ := strconv.Atoi(os.Getenv("MASK"))
	CallClear()
	switch {
	case address == "" && mask == 0:
		fmt.Print("[?] Enter IP address: ")
		_, _ = fmt.Scanf("%s", &address)
		fmt.Print("[?] Enter mask: ")
		_, _ = fmt.Scanf("%d", &mask)
		return address, mask
	case address == "":
		printWrn("Mask got from env")
		fmt.Print("[?] Enter IP address: ")
		_, _ = fmt.Scanf("%s", &address)
		return address, mask
	case mask == 0:
		printWrn("IP got from env")
		fmt.Print("[?] Enter mask: ")
		_, _ = fmt.Scanf("%d", &mask)
		return address, mask
	default:
		printWrn("IP address & mask got from env")
		return address, mask
	}
}

func dropIpAdd(address string, mask int) NetModel {
	droppedIP := strings.Split(address, ".")
	t1, _ := strconv.Atoi(droppedIP[0])
	t2, _ := strconv.Atoi(droppedIP[1])
	t3, _ := strconv.Atoi(droppedIP[2])
	t4, _ := strconv.Atoi(droppedIP[3])
	return NetModel{t1, t2, t3, t4, mask, "", 0}
}

func ConvertInt(val string, base, toBase int) (string, error) {
	i, err := strconv.ParseInt(val, base, 64)
	if err != nil {
		return "", err
	}
	based := strconv.FormatInt(i, toBase)
	if len(based) != 8 {
		repeater := 8 - len(based)
		based = strings.Repeat("0", repeater) + based
	}
	return based, nil
}

func getNetMask(mask int) NetModel {
	switch mask {
	case 8:
		return NetModel{255,0,0,0, 0, "1", 16777214}
	case 16:
		return NetModel{255,255,0,0, 0, "2", 65534}
	case 24:
		return NetModel{255,255,255,0, 0, "3", 254}
	case 25:
		return NetModel{255,255,255,128, 0, "3", 126}
	case 26:
		return NetModel{255,255,255,192, 0, "3", 62}
	case 27:
		return NetModel{255,255,255,224, 0, "3", 30}
	case 28:
		return NetModel{255,255,255,240, 0, "3", 14}
	case 29:
		return NetModel{255,255,255,248, 0, "3", 6}
	case 30:
		return NetModel{255,255,255,252, 0, "3", 2}
	default:
		return NetModel{0,0,0,0, 0, "0", 4294967294}
	}
}

func turnToBin(model NetModel, tb int, net NetModel) string {
	t1, _ := ConvertInt(strconv.Itoa(model.o1), 10, tb)
	t2, _ := ConvertInt(strconv.Itoa(model.o2), 10, tb)
	t3, _ := ConvertInt(strconv.Itoa(model.o3), 10, tb)
	t4, _ := ConvertInt(strconv.Itoa(model.o4), 10, tb)
	switch net.sep {
	case "1":
		separator := strings.Join([]string{t1, t2}, " | ")
		return strings.Join([]string{separator, t3, t4}, ".")
	case "2":
		separator := strings.Join([]string{t2, t3}, " | ")
		return strings.Join([]string{t1, separator, t4}, ".")
	case "3":
		separator := strings.Join([]string{t3, t4}, " | ")
		return strings.Join([]string{t1, t2, separator}, ".")
	default:
		return strings.Join([]string{t1, t2, t3, t4}, ".")
	}
}

func getMeta(ip NetModel, network NetModel, t1, t2, t3, t4 int) NetModel {
	switch network.sep {
	case "1":
		return NetModel{ip.o1, t2, t3, t4, 0, "", 0}
	case "2":
		return NetModel{ip.o1, ip.o2, t3, t4, 0, "", 0}
	case "3":
		return NetModel{ip.o1, ip.o2, ip.o3, t4, 0, "", 0}
	default:
		return NetModel{t1, t2, t3, t4, 0, "", 0}
	}
}

func main() {
	var variant int
	var address string
	var mask int

	CallClear()
	P1:
	fmt.Printf(" [1] Get public IP (info only) \n" +
		" [2] Analyze interface IP \n" +
		" [3] Enter other IP \n\n" +
		"[?] Your choice(enter number): ")
	_, _ = fmt.Scanf("%d", &variant)

	switch variant {
	case 1:
		CallClear()
		getPublicIP()
		goto P1
	case 2:
		address, mask = getInterfaces()
	case 3:
		address, mask = getManualIP()
	default:
		CallClear()
		printErr("Wrong variant!", strconv.Itoa(variant))
		goto P1
	}
	if address == "" {
		CallClear()
		printErr("Wrong IP!", address)
		goto P1
	}
	CallClear()

	fullIp := dropIpAdd(address, mask)
	netmask := getNetMask(mask)

	fullIpBin := turnToBin(fullIp, 2, netmask)
	netmaskBin := turnToBin(netmask, 2, netmask)

	network := getMeta(fullIp, netmask, 0, 0, 0, 0)
	broadcast := getMeta(fullIp, netmask, 255, 255, 255, 255)
	minHost := getMeta(fullIp, netmask, 0, 0, 0, 1)
	maxHost := getMeta(fullIp, netmask, 0, 0, 0, 254)

	print4(fullIp.o1, fullIp.o2, fullIp.o3, fullIp.o4, "IP")
	printBin(strconv.Itoa(fullIp.mask), "BITMASK")
	printBin(fullIpBin, "IP BINARY")
	print4(netmask.o1, netmask.o2, netmask.o3, netmask.o4, "NETMASK")
	printBin(netmaskBin, "NM BINARY")
	print4(network.o1, network.o2, network.o3, network.o4, "NETWORK")
	print4(broadcast.o1, broadcast.o2, broadcast.o3, broadcast.o4, "BROADCAST")
	print4(minHost.o1, minHost.o2, minHost.o3, minHost.o4, "MIN HOST")
	print4(maxHost.o1, maxHost.o2, maxHost.o3, maxHost.o4, "MAX HOST")
	printBin(strconv.Itoa(netmask.hosts), "HOSTS")
}
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
)

var clear map[string]func()

type NetModel struct {
	o1, o2, o3, o4, mask int
	sep string
	hosts int
}

func init() {
	clear = make(map[string]func())
	clear["linux"] = func() {
		cmd := exec.Command("clear")
		cmd.Stdout = os.Stdout
		_ = cmd.Run()
	}
	clear["windows"] = func() {
		cmd := exec.Command("cmd", "/c", "cls")
		cmd.Stdout = os.Stdout
		_ = cmd.Run()
	}
}

func printHeader() {
	fmt.Printf("-------[ IP AUTO CALC v0.1 ]------- \n\n")
}
func print4(t1, t2, t3, t4 int, word string) {
	fmt.Printf("[+] %s: %d.%d.%d.%d \n", word, t1, t2, t3, t4)
}
func printBin(t string, word string) {
	fmt.Printf("[+] %s: %s \n", word, t)
}
func printErr(text, code string) {
	fmt.Printf("[!] ERROR(%s): %s\n\n", code, text)
}
func printWrn(text string) {
	fmt.Printf("[-] INFO: %s\n", text)
}

func CallClear() {
	value, ok := clear[runtime.GOOS]
	if ok {
		value()
	} else {
		for i := 0; i < 20; i++ {
			fmt.Printf("\n\n\n\n\n\n\n")
		}
	}
	printHeader()
}

func getInterfaces() (string, int) {
	// Get all interfaces have access
	interfaces, err := net.Interfaces()
	if err != nil {
		panic(err)
	}
	CallClear()
	for _, intFace := range interfaces {
		// Address array for every network interface
		adds, err := intFace.Addrs()
		if err != nil {
			panic(err)
		}
		//fmt.Printf("Network interface: %s\n", intFace.Name)
		for _, add := range adds {
			CallClear()
			if ip, ok := add.(*net.IPNet); ok {
				fmt.Print("IP: ", ip)
				var input string
				fmt.Print(". Get this? [y/n]: ")
				_, _ = fmt.Scanf("%s", &input)
				if input == "y" || input == "yes" {
					m, _ := ip.Mask.Size()

					return ip.IP.String(), m
				} else {
					printWrn("Search for others IP...")
				}
			}
		}
	}
	return "", 0
}

func getPublicIP() {
	resp, err := http.Get("https://eth0.me")
	if err != nil {
		log.Fatalln(err)
	}
	body, _ := ioutil.ReadAll(resp.Body)
	p := strings.Replace(string(body), "\n", "", 1)
	fmt.Printf("[+] PUBLIC IP: %s\n\n", p)
}

func getManualIP() (string, int) {
	address := os.Getenv("ADDRESS")
	mask, _ := strconv.Atoi(os.Getenv("MASK"))
	CallClear()
	switch {
	case address == "" && mask == 0:
		fmt.Print("[?] Enter IP address: ")
		_, _ = fmt.Scanf("%s", &address)
		fmt.Print("[?] Enter mask: ")
		_, _ = fmt.Scanf("%d", &mask)
		return address, mask
	case address == "":
		printWrn("Mask got from env")
		fmt.Print("[?] Enter IP address: ")
		_, _ = fmt.Scanf("%s", &address)
		return address, mask
	case mask == 0:
		printWrn("IP got from env")
		fmt.Print("[?] Enter mask: ")
		_, _ = fmt.Scanf("%d", &mask)
		return address, mask
	default:
		printWrn("IP address & mask got from env")
		return address, mask
	}
}

func dropIpAdd(address string, mask int) NetModel {
	droppedIP := strings.Split(address, ".")
	t1, _ := strconv.Atoi(droppedIP[0])
	t2, _ := strconv.Atoi(droppedIP[1])
	t3, _ := strconv.Atoi(droppedIP[2])
	t4, _ := strconv.Atoi(droppedIP[3])
	return NetModel{t1, t2, t3, t4, mask, "", 0}
}

func ConvertInt(val string, base, toBase int) (string, error) {
	i, err := strconv.ParseInt(val, base, 64)
	if err != nil {
		return "", err
	}
	based := strconv.FormatInt(i, toBase)
	if len(based) != 8 {
		repeater := 8 - len(based)
		based = strings.Repeat("0", repeater) + based
	}
	return based, nil
}

func getNetMask(mask int) NetModel {
	switch mask {
	case 8:
		return NetModel{255,0,0,0, 0, "1", 16777214}
	case 16:
		return NetModel{255,255,0,0, 0, "2", 65534}
	case 24:
		return NetModel{255,255,255,0, 0, "3", 254}
	case 25:
		return NetModel{255,255,255,128, 0, "3", 126}
	case 26:
		return NetModel{255,255,255,192, 0, "3", 62}
	case 27:
		return NetModel{255,255,255,224, 0, "3", 30}
	case 28:
		return NetModel{255,255,255,240, 0, "3", 14}
	case 29:
		return NetModel{255,255,255,248, 0, "3", 6}
	case 30:
		return NetModel{255,255,255,252, 0, "3", 2}
	default:
		return NetModel{0,0,0,0, 0, "0", 4294967294}
	}
}

func turnToBin(model NetModel, tb int, net NetModel) string {
	t1, _ := ConvertInt(strconv.Itoa(model.o1), 10, tb)
	t2, _ := ConvertInt(strconv.Itoa(model.o2), 10, tb)
	t3, _ := ConvertInt(strconv.Itoa(model.o3), 10, tb)
	t4, _ := ConvertInt(strconv.Itoa(model.o4), 10, tb)
	switch net.sep {
	case "1":
		separator := strings.Join([]string{t1, t2}, " | ")
		return strings.Join([]string{separator, t3, t4}, ".")
	case "2":
		separator := strings.Join([]string{t2, t3}, " | ")
		return strings.Join([]string{t1, separator, t4}, ".")
	case "3":
		separator := strings.Join([]string{t3, t4}, " | ")
		return strings.Join([]string{t1, t2, separator}, ".")
	default:
		return strings.Join([]string{t1, t2, t3, t4}, ".")
	}
}

func getMeta(ip NetModel, network NetModel, t1, t2, t3, t4 int) NetModel {
	switch network.sep {
	case "1":
		return NetModel{ip.o1, t2, t3, t4, 0, "", 0}
	case "2":
		return NetModel{ip.o1, ip.o2, t3, t4, 0, "", 0}
	case "3":
		return NetModel{ip.o1, ip.o2, ip.o3, t4, 0, "", 0}
	default:
		return NetModel{t1, t2, t3, t4, 0, "", 0}
	}
}

func main() {
	var variant int
	var address string
	var mask int

	CallClear()
	P1:
	fmt.Printf(" [1] Get public IP (info only) \n" +
		" [2] Analyze interface IP \n" +
		" [3] Enter other IP \n\n" +
		"[?] Your choice(enter number): ")
	_, _ = fmt.Scanf("%d", &variant)

	switch variant {
	case 1:
		CallClear()
		getPublicIP()
		goto P1
	case 2:
		address, mask = getInterfaces()
	case 3:
		address, mask = getManualIP()
	default:
		CallClear()
		printErr("Wrong variant!", strconv.Itoa(variant))
		goto P1
	}
	if address == "" {
		CallClear()
		printErr("Wrong IP!", address)
		goto P1
	}
	CallClear()

	fullIp := dropIpAdd(address, mask)
	netmask := getNetMask(mask)

	fullIpBin := turnToBin(fullIp, 2, netmask)
	netmaskBin := turnToBin(netmask, 2, netmask)

	network := getMeta(fullIp, netmask, 0, 0, 0, 0)
	broadcast := getMeta(fullIp, netmask, 255, 255, 255, 255)
	minHost := getMeta(fullIp, netmask, 0, 0, 0, 1)
	maxHost := getMeta(fullIp, netmask, 0, 0, 0, 254)

	print4(fullIp.o1, fullIp.o2, fullIp.o3, fullIp.o4, "IP")
	printBin(strconv.Itoa(fullIp.mask), "BITMASK")
	printBin(fullIpBin, "IP BINARY")
	print4(netmask.o1, netmask.o2, netmask.o3, netmask.o4, "NETMASK")
	printBin(netmaskBin, "NM BINARY")
	print4(network.o1, network.o2, network.o3, network.o4, "NETWORK")
	print4(broadcast.o1, broadcast.o2, broadcast.o3, broadcast.o4, "BROADCAST")
	print4(minHost.o1, minHost.o2, minHost.o3, minHost.o4, "MIN HOST")
	print4(maxHost.o1, maxHost.o2, maxHost.o3, maxHost.o4, "MAX HOST")
	printBin(strconv.Itoa(netmask.hosts), "HOSTS")
}