前言
最近做项目,发现内网环境下基本还是ipv4,但是在网络隔离后,需要开墙,开墙需要计算网段,本来也没什么,手工计算一下就行,但是开墙多了计算也很烦,其实做一个网页工具最合适,但是笔者做了一个桌面工具,免得维护,使用go fyne桌面简单做了一个,可以跨平台。附上我自己ARM mac编译的软件。
demo
go开发环境:包括goproxy ide等,fyne的文档:https://docs.fyne.io/started/quick/
执行go get fyne.io/fyne/v2@latest
最新版本是2.7.2
正常写代码
Go
package main
import (
"fmt"
"strconv"
"strings"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
)
// client use, for server not use global var
var ipv4, netmask string
func main() {
// build ui for window
demoApp := app.New()
// window must init for other ui first
demoWin := demoApp.NewWindow("net-segment")
// def input and output entry
// input for ip
ipv4Entry := widget.NewEntry()
ipv4Entry.Move(fyne.NewPos(0, 0))
ipv4Entry.Resize(fyne.NewSize(200, ipv4Entry.MinSize().Height))
ipv4Entry.SetPlaceHolder("IPv4 Address")
ipv4Entry.OnChanged = func(s string) {
ipv4 = s
}
// subnet mask
subNetmaskEntry := widget.NewEntry()
subNetmaskEntry.SetPlaceHolder("SubnetMask")
subNetmaskEntry.OnChanged = func(s string) {
netmask = s
}
// def net segment for output
netSegmentEntry := widget.NewEntry()
netSegmentEntry.SetPlaceHolder("NetSegment")
netSegmentEntry.OnChanged = func(s string) {
fmt.Println(s)
}
//def button for calc
submitButton := widget.NewButton("Calc netSegment", func() {
// get data & calc
// not check null | empty, no need for client self use
fmt.Println("Calc netSegment ......")
ips := strings.Split(ipv4, ".")
subNetmaskIps := strings.Split(netmask, ".")
var segNum = 0
var result string
for i := 0; i < len(ips); i++ {
ipSeg, _ := strconv.ParseInt(ips[i], 10, 64)
ipSeg2 := strconv.FormatInt(ipSeg, 2)
ipSeg2 = fmt.Sprintf("%08s", ipSeg2)
maskSeg, _ := strconv.ParseInt(subNetmaskIps[i], 10, 64)
maskSeg2 := strconv.FormatInt(maskSeg, 2)
maskSeg2 = fmt.Sprintf("%08s", maskSeg2)
var builder strings.Builder
for j := 0; j < 8; j++ {
if maskSeg2[j] == '1' {
segNum++
builder.WriteByte(ipSeg2[j])
} else {
builder.WriteByte('0')
}
}
ipSeg, _ = strconv.ParseInt(builder.String(), 2, 64)
ipSeg10 := strconv.FormatInt(ipSeg, 10)
result += ipSeg10 + "."
}
result = result[:len(result)-1] + "/" + strconv.Itoa(segNum)
netSegmentEntry.SetText(result)
})
ipv4Item := widget.NewFormItem("IPv4 Address", ipv4Entry)
subNetmaskItem := widget.NewFormItem("SubnetMask", subNetmaskEntry)
formIn := widget.NewForm(ipv4Item, subNetmaskItem)
netSegmentBoxItem := widget.NewFormItem("NetSegment", netSegmentEntry)
netSegmentForm := widget.NewForm(netSegmentBoxItem)
content := container.NewVBox(formIn, submitButton, netSegmentForm)
demoWin.SetContent(content)
demoWin.SetFixedSize(true)
demoWin.Resize(fyne.NewSize(300, 160))
demoWin.ShowAndRun()
}
使用了form,免得自己调各种样式,这里要注意window一定要先定义
另外计算网段没有使用位运算,如果是服务端,建议使用位运算,虽然难写和理解,但是效率高很多。
结果

测试多次均正确,因为是同环境,如果跨环境,涉及cgo交叉编译,比较麻烦,window的开发涉及系统的UI,fyne没有内置,使用的系统UI函数,所以,需要把相关的dll so dylib纳入项目。
总结
其实就是没有现成的工具,笔者需要计算内网的网段,执行开墙,本来服务端写是最好的,大家都可以使用,但是笔者不想维护环境,不是很想为了这个功能专门部署,所以写了一个客户端,如果跨环境使用,cgo交叉编译麻烦,建议在对应的环境服务器编译。