Fix lint errors

This commit is contained in:
世界 2026-06-22 15:49:11 +08:00
parent a9f4123ba2
commit 46aa536b37
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
41 changed files with 498 additions and 406 deletions

View file

@ -16,21 +16,56 @@ on:
jobs: jobs:
build: build:
name: Build name: Lint ${{ matrix.goos }}/${{ matrix.goarch }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- goos: windows
goarch: amd64
- goos: windows
goarch: '386'
- goos: windows
goarch: arm64
- goos: linux
goarch: amd64
- goos: linux
goarch: arm64
- goos: linux
goarch: arm
- goos: linux
goarch: '386'
- goos: darwin
goarch: amd64
- goos: darwin
goarch: arm64
- goos: android
goarch: arm64
- goos: freebsd
goarch: amd64
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: ^1.25 go-version: ^1.25
- name: Cache go module
uses: actions/cache@v4
with:
path: |
~/go/pkg/mod
key: go-${{ hashFiles('**/go.sum') }}
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v8 uses: golangci/golangci-lint-action@v8
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
with: with:
version: latest version: latest
args: --timeout=30m args: --timeout=30m
install-mode: binary install-mode: binary
verify: false verify: false

View file

@ -1,35 +1,24 @@
version: "2" version: "2"
run: run:
go: "1.25" go: "1.24"
linters: linters:
default: none default: none
enable: enable:
- govet
- ineffassign - ineffassign
- paralleltest
- staticcheck - staticcheck
- modernize
settings: settings:
staticcheck: staticcheck:
checks: checks:
- all - all
- -S1000 - -QF1008 # could remove embedded field "<interface>" from selector
- -S1008 - -ST1003 # should not use ALL_CAPS in Go names; use CamelCase instead
- -S1017 - -QF1001 # could apply De Morgan's law
- -ST1003
- -QF1001
- -QF1003
- -QF1008
exclusions: exclusions:
generated: lax generated: lax
presets: presets:
- comments - comments
- common-false-positives - common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
formatters: formatters:
enable: enable:
- gci - gci
@ -42,8 +31,4 @@ formatters:
- default - default
custom-order: true custom-order: true
exclusions: exclusions:
generated: lax generated: lax
paths:
- third_party$
- builtin$
- examples$

View file

@ -18,11 +18,10 @@ fmt_install:
go install -v github.com/daixiang0/gci@latest go install -v github.com/daixiang0/gci@latest
lint: lint:
GOOS=linux golangci-lint run . GOOS=linux golangci-lint --max-same-issues=0 --max-issues-per-linter=0 run ./...
GOOS=android golangci-lint run . GOOS=android golangci-lint --max-same-issues=0 --max-issues-per-linter=0 run ./...
GOOS=windows golangci-lint run . GOOS=windows golangci-lint --max-same-issues=0 --max-issues-per-linter=0 run ./...
GOOS=darwin golangci-lint run . GOOS=darwin golangci-lint --max-same-issues=0 --max-issues-per-linter=0 run ./...
GOOS=freebsd golangci-lint run .
lint_install: lint_install:
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest

View file

@ -10,7 +10,7 @@ import (
func BenchmarkTsChecksum(b *testing.B) { func BenchmarkTsChecksum(b *testing.B) {
packet := make([][]byte, 1000) packet := make([][]byte, 1000)
for i := 0; i < 1000; i++ { for i := range 1000 {
packet[i] = make([]byte, 1500) packet[i] = make([]byte, 1500)
rand.Read(packet[i]) rand.Read(packet[i])
} }
@ -22,7 +22,7 @@ func BenchmarkTsChecksum(b *testing.B) {
func BenchmarkGChecksum(b *testing.B) { func BenchmarkGChecksum(b *testing.B) {
packet := make([][]byte, 1000) packet := make([][]byte, 1000)
for i := 0; i < 1000; i++ { for i := range 1000 {
packet[i] = make([]byte, 1500) packet[i] = make([]byte, 1500)
rand.Read(packet[i]) rand.Read(packet[i])
} }

View file

@ -35,6 +35,9 @@
// only use the first FD to write outbound packets. Once 5 tuple hashes for // only use the first FD to write outbound packets. Once 5 tuple hashes for
// all outbound packets are available we will make use of all underlying FD's to // all outbound packets are available we will make use of all underlying FD's to
// write outbound packets. // write outbound packets.
//go:build darwin
package fdbased package fdbased
import ( import (
@ -46,7 +49,7 @@ import (
"github.com/sagernet/gvisor/pkg/tcpip" "github.com/sagernet/gvisor/pkg/tcpip"
"github.com/sagernet/gvisor/pkg/tcpip/header" "github.com/sagernet/gvisor/pkg/tcpip/header"
"github.com/sagernet/gvisor/pkg/tcpip/stack" "github.com/sagernet/gvisor/pkg/tcpip/stack"
"github.com/sagernet/sing-tun/internal/rawfile_darwin" rawfile "github.com/sagernet/sing-tun/internal/rawfile_darwin"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"

View file

@ -1,3 +1,5 @@
//go:build darwin
package fdbased package fdbased
import ( import (
@ -92,5 +94,5 @@ func endpointinitLockNames() {}
func init() { func init() {
endpointinitLockNames() endpointinitLockNames()
endpointprefixIndex = locking.NewMutexClass(reflect.TypeOf(endpointRWMutex{}), endpointlockNames) endpointprefixIndex = locking.NewMutexClass(reflect.TypeFor[endpointRWMutex](), endpointlockNames)
} }

View file

@ -1,3 +1,5 @@
//go:build darwin
package fdbased package fdbased
import ( import (

View file

@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//go:build darwin
package fdbased package fdbased
import ( import (
@ -19,7 +21,7 @@ import (
"github.com/sagernet/gvisor/pkg/tcpip" "github.com/sagernet/gvisor/pkg/tcpip"
"github.com/sagernet/gvisor/pkg/tcpip/stack" "github.com/sagernet/gvisor/pkg/tcpip/stack"
"github.com/sagernet/gvisor/pkg/tcpip/stack/gro" "github.com/sagernet/gvisor/pkg/tcpip/stack/gro"
"github.com/sagernet/sing-tun/internal/rawfile_darwin" rawfile "github.com/sagernet/sing-tun/internal/rawfile_darwin"
"github.com/sagernet/sing-tun/internal/stopfd_darwin" "github.com/sagernet/sing-tun/internal/stopfd_darwin"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
@ -177,7 +179,7 @@ func (d *recvMMsgDispatcher) dispatch() (bool, tcpip.Error) {
d.gro.Dispatcher = dsp d.gro.Dispatcher = dsp
defer d.pkts.Reset() defer d.pkts.Reset()
for k := 0; k < nMsgs; k++ { for k := range nMsgs {
n := int(d.msgHdrs[k].DataLen) n := int(d.msgHdrs[k].DataLen)
payload := d.bufs[k].pullBuffer(n) payload := d.bufs[k].pullBuffer(n)
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{

View file

@ -1,3 +1,5 @@
//go:build darwin
package fdbased package fdbased
import ( import (
@ -60,5 +62,5 @@ func processorinitLockNames() {}
func init() { func init() {
processorinitLockNames() processorinitLockNames()
processorprefixIndex = locking.NewMutexClass(reflect.TypeOf(processorMutex{}), processorlockNames) processorprefixIndex = locking.NewMutexClass(reflect.TypeFor[processorMutex](), processorlockNames)
} }

View file

@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//go:build darwin
package fdbased package fdbased
import ( import (

View file

@ -878,7 +878,7 @@ func (o NDPDNSSearchList) iterDomainNames(fn func(string)) error {
} }
// Copy the label and add a trailing period. // Copy the label and add a trailing period.
for i := 0; i < labelLen; i++ { for i := range labelLen {
b, err := searchList.ReadByte() b, err := searchList.ReadByte()
if err != nil { if err != nil {
if err != io.EOF { if err != io.EOF {

View file

@ -476,20 +476,14 @@ func ParseSynOptions(opts []byte, isAck bool) TCPSynOptions {
if mss == 0 { if mss == 0 {
return synOpts return synOpts
} }
synOpts.MSS = mss synOpts.MSS = max(mss, TCPMinimumSendMSS)
if mss < TCPMinimumSendMSS {
synOpts.MSS = TCPMinimumSendMSS
}
i += 4 i += 4
case TCPOptionWS: case TCPOptionWS:
if i+3 > limit || opts[i+1] != 3 { if i+3 > limit || opts[i+1] != 3 {
return synOpts return synOpts
} }
ws := int(opts[i+2]) ws := min(int(opts[i+2]), MaxWndScale)
if ws > MaxWndScale {
ws = MaxWndScale
}
synOpts.WS = ws synOpts.WS = ws
i += 3 i += 3
@ -561,7 +555,7 @@ func ParseTCPOptions(b []byte) TCPOptions {
} }
numBlocks := (sackOptionLen - 2) / 8 numBlocks := (sackOptionLen - 2) / 8
opts.SACKBlocks = []SACKBlock{} opts.SACKBlocks = []SACKBlock{}
for j := 0; j < numBlocks; j++ { for j := range numBlocks {
start := binary.BigEndian.Uint32(b[i+2+j*8:]) start := binary.BigEndian.Uint32(b[i+2+j*8:])
end := binary.BigEndian.Uint32(b[i+2+j*8+4:]) end := binary.BigEndian.Uint32(b[i+2+j*8+4:])
opts.SACKBlocks = append(opts.SACKBlocks, SACKBlock{ opts.SACKBlocks = append(opts.SACKBlocks, SACKBlock{
@ -646,10 +640,7 @@ func EncodeSACKBlocks(sackBlocks []SACKBlock, b []byte) int {
if len(sackBlocks) == 0 { if len(sackBlocks) == 0 {
return 0 return 0
} }
l := len(sackBlocks) l := min(len(sackBlocks), TCPMaxSACKBlocks)
if l > TCPMaxSACKBlocks {
l = TCPMaxSACKBlocks
}
if ll := (len(b) - 2) / 8; ll < l { if ll := (len(b) - 2) / 8; ll < l {
l = ll l = ll
} }

View file

@ -245,6 +245,53 @@ func (a Address) Len() int {
return a.length return a.length
} }
// String implements the fmt.Stringer interface.
func (a Address) String() string {
switch l := a.Len(); l {
case 4:
return fmt.Sprintf("%d.%d.%d.%d", int(a.addr[0]), int(a.addr[1]), int(a.addr[2]), int(a.addr[3]))
case 16:
// Find the longest subsequence of hexadecimal zeros.
start, end := -1, -1
for i := 0; i < a.Len(); i += 2 {
j := i
for j < a.Len() && a.addr[j] == 0 && a.addr[j+1] == 0 {
j += 2
}
if j > i+2 && j-i > end-start {
start, end = i, j
}
}
var b strings.Builder
for i := 0; i < a.Len(); i += 2 {
if i == start {
b.WriteString("::")
i = end
if end >= a.Len() {
break
}
} else if i > 0 {
b.WriteByte(':')
}
v := uint16(a.addr[i+0])<<8 | uint16(a.addr[i+1])
if v == 0 {
b.WriteByte('0')
} else {
const digits = "0123456789abcdef"
for i := uint(3); i < 4; i-- {
if v := v >> (i * 4); v != 0 {
b.WriteByte(digits[v&0xf])
}
}
}
}
return b.String()
default:
return fmt.Sprintf("%x", a.addr[:l])
}
}
// WithPrefix returns the address with a prefix that represents a point subnet. // WithPrefix returns the address with a prefix that represents a point subnet.
func (a Address) WithPrefix() AddressWithPrefix { func (a Address) WithPrefix() AddressWithPrefix {
return AddressWithPrefix{ return AddressWithPrefix{
@ -541,7 +588,7 @@ func (a AddressWithPrefix) Subnet() Subnet {
address: a.Address, address: a.Address,
mask: AddressMask{length: addrLen}, mask: AddressMask{length: addrLen},
} }
for i := 0; i < addrLen; i++ { for i := range addrLen {
sub.mask.mask[i] = 0xff sub.mask.mask[i] = 0xff
} }
return sub return sub
@ -550,7 +597,7 @@ func (a AddressWithPrefix) Subnet() Subnet {
sa := Address{length: addrLen} sa := Address{length: addrLen}
sm := AddressMask{length: addrLen} sm := AddressMask{length: addrLen}
n := uint(a.PrefixLen) n := uint(a.PrefixLen)
for i := 0; i < addrLen; i++ { for i := range addrLen {
if n >= 8 { if n >= 8 {
sa.addr[i] = a.Address.addr[i] sa.addr[i] = a.Address.addr[i]
sm.mask[i] = 0xff sm.mask[i] = 0xff

View file

@ -1,7 +1,8 @@
//go:build darwin
package rawfile package rawfile
import ( import (
"reflect"
"unsafe" "unsafe"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
@ -25,12 +26,8 @@ func IovecFromBytes(bs []byte) unix.Iovec {
return iov return iov
} }
func bytesFromIovec(iov unix.Iovec) (bs []byte) { func bytesFromIovec(iov unix.Iovec) []byte {
sh := (*reflect.SliceHeader)(unsafe.Pointer(&bs)) return unsafe.Slice(iov.Base, iov.Len)
sh.Data = uintptr(unsafe.Pointer(iov.Base))
sh.Len = int(iov.Len)
sh.Cap = int(iov.Len)
return
} }
// AppendIovecFromBytes returns append(iovs, IovecFromBytes(bs)). If len(bs) == // AppendIovecFromBytes returns append(iovs, IovecFromBytes(bs)). If len(bs) ==
@ -56,6 +53,7 @@ type MsgHdrX struct {
} }
func NonBlockingSendMMsg(fd int, msgHdrs []MsgHdrX) (int, unix.Errno) { func NonBlockingSendMMsg(fd int, msgHdrs []MsgHdrX) (int, unix.Errno) {
//nolint:staticcheck
n, _, e := unix.RawSyscall6(unix.SYS_SENDMSG_X, uintptr(fd), uintptr(unsafe.Pointer(&msgHdrs[0])), uintptr(len(msgHdrs)), unix.MSG_DONTWAIT, 0, 0) n, _, e := unix.RawSyscall6(unix.SYS_SENDMSG_X, uintptr(fd), uintptr(unsafe.Pointer(&msgHdrs[0])), uintptr(len(msgHdrs)), unix.MSG_DONTWAIT, 0, 0)
return int(n), e return int(n), e
} }
@ -66,12 +64,14 @@ const SizeofMsgHdrX = unsafe.Sizeof(MsgHdrX{})
// It fails if partial data is written. // It fails if partial data is written.
func NonBlockingWriteIovec(fd int, iovec []unix.Iovec) unix.Errno { func NonBlockingWriteIovec(fd int, iovec []unix.Iovec) unix.Errno {
iovecLen := uintptr(len(iovec)) iovecLen := uintptr(len(iovec))
//nolint:staticcheck
_, _, e := unix.RawSyscall(unix.SYS_WRITEV, uintptr(fd), uintptr(unsafe.Pointer(&iovec[0])), iovecLen) _, _, e := unix.RawSyscall(unix.SYS_WRITEV, uintptr(fd), uintptr(unsafe.Pointer(&iovec[0])), iovecLen)
return e return e
} }
func BlockingReadvUntilStopped(efd int, fd int, iovecs []unix.Iovec) (int, unix.Errno) { func BlockingReadvUntilStopped(efd int, fd int, iovecs []unix.Iovec) (int, unix.Errno) {
for { for {
//nolint:staticcheck
n, _, e := unix.RawSyscall(unix.SYS_READV, uintptr(fd), uintptr(unsafe.Pointer(&iovecs[0])), uintptr(len(iovecs))) n, _, e := unix.RawSyscall(unix.SYS_READV, uintptr(fd), uintptr(unsafe.Pointer(&iovecs[0])), uintptr(len(iovecs)))
if e == 0 { if e == 0 {
return int(n), 0 return int(n), 0
@ -91,6 +91,7 @@ func BlockingReadvUntilStopped(efd int, fd int, iovecs []unix.Iovec) (int, unix.
func BlockingRecvMMsgUntilStopped(efd int, fd int, msgHdrs []MsgHdrX) (int, unix.Errno) { func BlockingRecvMMsgUntilStopped(efd int, fd int, msgHdrs []MsgHdrX) (int, unix.Errno) {
for { for {
//nolint:staticcheck
n, _, e := unix.RawSyscall6(unix.SYS_RECVMSG_X, uintptr(fd), uintptr(unsafe.Pointer(&msgHdrs[0])), uintptr(len(msgHdrs)), unix.MSG_DONTWAIT, 0, 0) n, _, e := unix.RawSyscall6(unix.SYS_RECVMSG_X, uintptr(fd), uintptr(unsafe.Pointer(&msgHdrs[0])), uintptr(len(msgHdrs)), unix.MSG_DONTWAIT, 0, 0)
if e == 0 { if e == 0 {
return int(n), e return int(n), e
@ -162,7 +163,7 @@ func BlockingPollUntilStopped(efd int, fd int, events int16) (bool, unix.Errno)
var efdHasData bool var efdHasData bool
var errno unix.Errno var errno unix.Errno
for i := 0; i < n; i++ { for i := range n {
ev := &revents[i] ev := &revents[i]
if int(ev.Ident) == efd && ev.Filter == unix.EVFILT_READ { if int(ev.Ident) == efd && ev.Filter == unix.EVFILT_READ {

View file

@ -1,3 +1,5 @@
//go:build darwin
package stopfd package stopfd
import ( import (

View file

@ -98,105 +98,105 @@ func firewallRuleAdd(name, description, group, appPath, serviceName, ports, remo
if profile == NET_FW_PROFILE2_CURRENT { if profile == NET_FW_PROFILE2_CURRENT {
currentProfiles, err := oleutil.GetProperty(fwPolicy, "CurrentProfileTypes") currentProfiles, err := oleutil.GetProperty(fwPolicy, "CurrentProfileTypes")
if err != nil { if err != nil {
return false, fmt.Errorf("Failed to get CurrentProfiles: %s", err) return false, fmt.Errorf("failed to get CurrentProfiles: %s", err)
} }
profile = currentProfiles.Value().(int32) profile = currentProfiles.Value().(int32)
} }
unknownRules, err := oleutil.GetProperty(fwPolicy, "Rules") unknownRules, err := oleutil.GetProperty(fwPolicy, "Rules")
if err != nil { if err != nil {
return false, fmt.Errorf("Failed to get Rules: %s", err) return false, fmt.Errorf("failed to get Rules: %s", err)
} }
rules := unknownRules.ToIDispatch() rules := unknownRules.ToIDispatch()
if ok, err := FirewallRuleExistsByName(rules, name); err != nil { if ok, err := FirewallRuleExistsByName(rules, name); err != nil {
return false, fmt.Errorf("Error while checking rules for duplicate: %s", err) return false, fmt.Errorf("error while checking rules for duplicate: %s", err)
} else if ok { } else if ok {
return false, nil return false, nil
} }
unknown2, err := oleutil.CreateObject("HNetCfg.FWRule") unknown2, err := oleutil.CreateObject("HNetCfg.FWRule")
if err != nil { if err != nil {
return false, fmt.Errorf("Error creating Rule object: %s", err) return false, fmt.Errorf("error creating Rule object: %s", err)
} }
defer unknown2.Release() defer unknown2.Release()
fwRule, err := unknown2.QueryInterface(ole.IID_IDispatch) fwRule, err := unknown2.QueryInterface(ole.IID_IDispatch)
if err != nil { if err != nil {
return false, fmt.Errorf("Error creating Rule object (2): %s", err) return false, fmt.Errorf("error creating Rule object (2): %s", err)
} }
defer fwRule.Release() defer fwRule.Release()
if _, err := oleutil.PutProperty(fwRule, "Name", name); err != nil { if _, err := oleutil.PutProperty(fwRule, "Name", name); err != nil {
return false, fmt.Errorf("Error setting property (Name) of Rule: %s", err) return false, fmt.Errorf("error setting property (Name) of Rule: %s", err)
} }
if _, err := oleutil.PutProperty(fwRule, "Description", description); err != nil { if _, err := oleutil.PutProperty(fwRule, "Description", description); err != nil {
return false, fmt.Errorf("Error setting property (Description) of Rule: %s", err) return false, fmt.Errorf("error setting property (Description) of Rule: %s", err)
} }
if appPath != "" { if appPath != "" {
if _, err := oleutil.PutProperty(fwRule, "Applicationname", appPath); err != nil { if _, err := oleutil.PutProperty(fwRule, "Applicationname", appPath); err != nil {
return false, fmt.Errorf("Error setting property (Applicationname) of Rule: %s", err) return false, fmt.Errorf("error setting property (Applicationname) of Rule: %s", err)
} }
} }
if serviceName != "" { if serviceName != "" {
if _, err := oleutil.PutProperty(fwRule, "ServiceName", serviceName); err != nil { if _, err := oleutil.PutProperty(fwRule, "ServiceName", serviceName); err != nil {
return false, fmt.Errorf("Error setting property (ServiceName) of Rule: %s", err) return false, fmt.Errorf("error setting property (ServiceName) of Rule: %s", err)
} }
} }
if protocol != 0 { if protocol != 0 {
if _, err := oleutil.PutProperty(fwRule, "Protocol", protocol); err != nil { if _, err := oleutil.PutProperty(fwRule, "Protocol", protocol); err != nil {
return false, fmt.Errorf("Error setting property (Protocol) of Rule: %s", err) return false, fmt.Errorf("error setting property (Protocol) of Rule: %s", err)
} }
} }
if icmpTypes != "" { if icmpTypes != "" {
if _, err := oleutil.PutProperty(fwRule, "IcmpTypesAndCodes", icmpTypes); err != nil { if _, err := oleutil.PutProperty(fwRule, "IcmpTypesAndCodes", icmpTypes); err != nil {
return false, fmt.Errorf("Error setting property (IcmpTypesAndCodes) of Rule: %s", err) return false, fmt.Errorf("error setting property (IcmpTypesAndCodes) of Rule: %s", err)
} }
} }
if ports != "" { if ports != "" {
if _, err := oleutil.PutProperty(fwRule, "LocalPorts", ports); err != nil { if _, err := oleutil.PutProperty(fwRule, "LocalPorts", ports); err != nil {
return false, fmt.Errorf("Error setting property (LocalPorts) of Rule: %s", err) return false, fmt.Errorf("error setting property (LocalPorts) of Rule: %s", err)
} }
} }
if remotePorts != "" { if remotePorts != "" {
if _, err := oleutil.PutProperty(fwRule, "RemotePorts", remotePorts); err != nil { if _, err := oleutil.PutProperty(fwRule, "RemotePorts", remotePorts); err != nil {
return false, fmt.Errorf("Error setting property (RemotePorts) of Rule: %s", err) return false, fmt.Errorf("error setting property (RemotePorts) of Rule: %s", err)
} }
} }
if localAddresses != "" { if localAddresses != "" {
if _, err := oleutil.PutProperty(fwRule, "LocalAddresses", localAddresses); err != nil { if _, err := oleutil.PutProperty(fwRule, "LocalAddresses", localAddresses); err != nil {
return false, fmt.Errorf("Error setting property (LocalAddresses) of Rule: %s", err) return false, fmt.Errorf("error setting property (LocalAddresses) of Rule: %s", err)
} }
} }
if remoteAddresses != "" { if remoteAddresses != "" {
if _, err := oleutil.PutProperty(fwRule, "RemoteAddresses", remoteAddresses); err != nil { if _, err := oleutil.PutProperty(fwRule, "RemoteAddresses", remoteAddresses); err != nil {
return false, fmt.Errorf("Error setting property (RemoteAddresses) of Rule: %s", err) return false, fmt.Errorf("error setting property (RemoteAddresses) of Rule: %s", err)
} }
} }
if direction != 0 { if direction != 0 {
if _, err := oleutil.PutProperty(fwRule, "Direction", direction); err != nil { if _, err := oleutil.PutProperty(fwRule, "Direction", direction); err != nil {
return false, fmt.Errorf("Error setting property (Direction) of Rule: %s", err) return false, fmt.Errorf("error setting property (Direction) of Rule: %s", err)
} }
} }
if _, err := oleutil.PutProperty(fwRule, "Enabled", enabled); err != nil { if _, err := oleutil.PutProperty(fwRule, "Enabled", enabled); err != nil {
return false, fmt.Errorf("Error setting property (Enabled) of Rule: %s", err) return false, fmt.Errorf("error setting property (Enabled) of Rule: %s", err)
} }
if _, err := oleutil.PutProperty(fwRule, "Grouping", group); err != nil { if _, err := oleutil.PutProperty(fwRule, "Grouping", group); err != nil {
return false, fmt.Errorf("Error setting property (Grouping) of Rule: %s", err) return false, fmt.Errorf("error setting property (Grouping) of Rule: %s", err)
} }
if _, err := oleutil.PutProperty(fwRule, "Profiles", profile); err != nil { if _, err := oleutil.PutProperty(fwRule, "Profiles", profile); err != nil {
return false, fmt.Errorf("Error setting property (Profiles) of Rule: %s", err) return false, fmt.Errorf("error setting property (Profiles) of Rule: %s", err)
} }
if _, err := oleutil.PutProperty(fwRule, "Action", action); err != nil { if _, err := oleutil.PutProperty(fwRule, "Action", action); err != nil {
return false, fmt.Errorf("Error setting property (Action) of Rule: %s", err) return false, fmt.Errorf("error setting property (Action) of Rule: %s", err)
} }
if edgeTraversal { if edgeTraversal {
if _, err := oleutil.PutProperty(fwRule, "EdgeTraversal", edgeTraversal); err != nil { if _, err := oleutil.PutProperty(fwRule, "EdgeTraversal", edgeTraversal); err != nil {
return false, fmt.Errorf("Error setting property (EdgeTraversal) of Rule: %s", err) return false, fmt.Errorf("error setting property (EdgeTraversal) of Rule: %s", err)
} }
} }
if _, err := oleutil.CallMethod(rules, "Add", fwRule); err != nil { if _, err := oleutil.CallMethod(rules, "Add", fwRule); err != nil {
return false, fmt.Errorf("Error adding Rule: %s", err) return false, fmt.Errorf("error adding Rule: %s", err)
} }
return true, nil return true, nil
@ -205,13 +205,13 @@ func firewallRuleAdd(name, description, group, appPath, serviceName, ports, remo
func FirewallRuleExistsByName(rules *ole.IDispatch, name string) (bool, error) { func FirewallRuleExistsByName(rules *ole.IDispatch, name string) (bool, error) {
enumProperty, err := rules.GetProperty("_NewEnum") enumProperty, err := rules.GetProperty("_NewEnum")
if err != nil { if err != nil {
return false, fmt.Errorf("Failed to get enumeration property on Rules: %s", err) return false, fmt.Errorf("failed to get enumeration property on Rules: %s", err)
} }
defer enumProperty.Clear() defer enumProperty.Clear()
enum, err := enumProperty.ToIUnknown().IEnumVARIANT(ole.IID_IEnumVariant) enum, err := enumProperty.ToIUnknown().IEnumVARIANT(ole.IID_IEnumVariant)
if err != nil { if err != nil {
return false, fmt.Errorf("Failed to cast enum to correct type: %s", err) return false, fmt.Errorf("failed to cast enum to correct type: %s", err)
} }
if enum == nil { if enum == nil {
return false, fmt.Errorf("can't get IEnumVARIANT, enum is nil") return false, fmt.Errorf("can't get IEnumVARIANT, enum is nil")
@ -219,7 +219,7 @@ func FirewallRuleExistsByName(rules *ole.IDispatch, name string) (bool, error) {
for itemRaw, length, err := enum.Next(1); length > 0; itemRaw, length, err = enum.Next(1) { for itemRaw, length, err := enum.Next(1); length > 0; itemRaw, length, err = enum.Next(1) {
if err != nil { if err != nil {
return false, fmt.Errorf("Failed to seek next Rule item: %s", err) return false, fmt.Errorf("failed to seek next Rule item: %s", err)
} }
t, err := func() (bool, error) { t, err := func() (bool, error) {
@ -227,7 +227,7 @@ func FirewallRuleExistsByName(rules *ole.IDispatch, name string) (bool, error) {
defer item.Release() defer item.Release()
if item, err := oleutil.GetProperty(item, "Name"); err != nil { if item, err := oleutil.GetProperty(item, "Name"); err != nil {
return false, fmt.Errorf("Failed to get Property (Name) of Rule") return false, fmt.Errorf("failed to get Property (Name) of Rule")
} else if item.ToString() == name { } else if item.ToString() == name {
return true, nil return true, nil
} }
@ -251,18 +251,18 @@ func FirewallRuleExistsByName(rules *ole.IDispatch, name string) (bool, error) {
func firewallAPIInit() (*ole.IUnknown, *ole.IDispatch, error) { func firewallAPIInit() (*ole.IUnknown, *ole.IDispatch, error) {
err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED) err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("Failed to initialize COM: %s", err) return nil, nil, fmt.Errorf("failed to initialize COM: %s", err)
} }
unknown, err := oleutil.CreateObject("HNetCfg.FwPolicy2") unknown, err := oleutil.CreateObject("HNetCfg.FwPolicy2")
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("Failed to create FwPolicy Object: %s", err) return nil, nil, fmt.Errorf("failed to create FwPolicy Object: %s", err)
} }
fwPolicy, err := unknown.QueryInterface(ole.IID_IDispatch) fwPolicy, err := unknown.QueryInterface(ole.IID_IDispatch)
if err != nil { if err != nil {
unknown.Release() unknown.Release()
return nil, nil, fmt.Errorf("Failed to create FwPolicy Object (2): %s", err) return nil, nil, fmt.Errorf("failed to create FwPolicy Object (2): %s", err)
} }
return unknown, fwPolicy, nil return unknown, fwPolicy, nil

View file

@ -1,3 +1,5 @@
//go:build windows
/* SPDX-License-Identifier: MIT /* SPDX-License-Identifier: MIT
* *
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved. * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.

View file

@ -1,3 +1,5 @@
//go:build windows
/* SPDX-License-Identifier: MIT /* SPDX-License-Identifier: MIT
* *
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved. * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.

View file

@ -1,3 +1,5 @@
//go:build windows
/* SPDX-License-Identifier: MIT /* SPDX-License-Identifier: MIT
* *
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved. * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.

View file

@ -1,3 +1,5 @@
//go:build windows
/* SPDX-License-Identifier: MIT /* SPDX-License-Identifier: MIT
* *
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved. * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
@ -60,9 +62,10 @@ const (
func (luid LUID) fallbackSetDNSForFamily(family AddressFamily, dnses []netip.Addr) error { func (luid LUID) fallbackSetDNSForFamily(family AddressFamily, dnses []netip.Addr) error {
var templateFlush string var templateFlush string
if family == windows.AF_INET { switch family {
case windows.AF_INET:
templateFlush = netshCmdTemplateFlush4 templateFlush = netshCmdTemplateFlush4
} else if family == windows.AF_INET6 { case windows.AF_INET6:
templateFlush = netshCmdTemplateFlush6 templateFlush = netshCmdTemplateFlush6
} }
@ -72,7 +75,7 @@ func (luid LUID) fallbackSetDNSForFamily(family AddressFamily, dnses []netip.Add
return err return err
} }
cmds = append(cmds, fmt.Sprintf(templateFlush, ipif.InterfaceIndex)) cmds = append(cmds, fmt.Sprintf(templateFlush, ipif.InterfaceIndex))
for i := 0; i < len(dnses); i++ { for i := range dnses {
if dnses[i].Is4() && family == windows.AF_INET { if dnses[i].Is4() && family == windows.AF_INET {
cmds = append(cmds, fmt.Sprintf(netshCmdTemplateAdd4, ipif.InterfaceIndex, dnses[i].String())) cmds = append(cmds, fmt.Sprintf(netshCmdTemplateAdd4, ipif.InterfaceIndex, dnses[i].String()))
} else if dnses[i].Is6() && family == windows.AF_INET6 { } else if dnses[i].Is6() && family == windows.AF_INET6 {
@ -85,23 +88,23 @@ func (luid LUID) fallbackSetDNSForFamily(family AddressFamily, dnses []netip.Add
func (luid LUID) fallbackSetDNSDomain(domain string) error { func (luid LUID) fallbackSetDNSDomain(domain string) error {
guid, err := luid.GUID() guid, err := luid.GUID()
if err != nil { if err != nil {
return fmt.Errorf("Error converting luid to guid: %w", err) return fmt.Errorf("error converting luid to guid: %w", err)
} }
key, err := registry.OpenKey(registry.LOCAL_MACHINE, fmt.Sprintf("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Adapters\\%v", guid), registry.QUERY_VALUE) key, err := registry.OpenKey(registry.LOCAL_MACHINE, fmt.Sprintf("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Adapters\\%v", guid), registry.QUERY_VALUE)
if err != nil { if err != nil {
return fmt.Errorf("Error opening adapter-specific TCP/IP network registry key: %w", err) return fmt.Errorf("error opening adapter-specific TCP/IP network registry key: %w", err)
} }
paths, _, err := key.GetStringsValue("IpConfig") paths, _, err := key.GetStringsValue("IpConfig")
key.Close() key.Close()
if err != nil { if err != nil {
return fmt.Errorf("Error reading IpConfig registry key: %w", err) return fmt.Errorf("error reading IpConfig registry key: %w", err)
} }
if len(paths) == 0 { if len(paths) == 0 {
return errors.New("No TCP/IP interfaces found on adapter") return errors.New("no TCP/IP interfaces found on adapter")
} }
key, err = registry.OpenKey(registry.LOCAL_MACHINE, fmt.Sprintf("SYSTEM\\CurrentControlSet\\Services\\%s", paths[0]), registry.SET_VALUE) key, err = registry.OpenKey(registry.LOCAL_MACHINE, fmt.Sprintf("SYSTEM\\CurrentControlSet\\Services\\%s", paths[0]), registry.SET_VALUE)
if err != nil { if err != nil {
return fmt.Errorf("Unable to open TCP/IP network registry key: %w", err) return fmt.Errorf("unable to open TCP/IP network registry key: %w", err)
} }
err = key.SetStringValue("Domain", domain) err = key.SetStringValue("Domain", domain)
key.Close() key.Close()

View file

@ -1,3 +1,5 @@
//go:build windows
/* SPDX-License-Identifier: MIT /* SPDX-License-Identifier: MIT
* *
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved. * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.

View file

@ -1,3 +1,5 @@
//go:build windows
/* SPDX-License-Identifier: MIT /* SPDX-License-Identifier: MIT
* *
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved. * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
@ -62,206 +64,206 @@ type IfType uint32
const ( const (
IfTypeOther IfType = 1 // None of the below IfTypeOther IfType = 1 // None of the below
IfTypeRegular1822 = 2 IfTypeRegular1822 IfType = 2
IfTypeHdh1822 = 3 IfTypeHdh1822 IfType = 3
IfTypeDdnX25 = 4 IfTypeDdnX25 IfType = 4
IfTypeRfc877X25 = 5 IfTypeRfc877X25 IfType = 5
IfTypeEthernetCSMACD = 6 IfTypeEthernetCSMACD IfType = 6
IfTypeISO88023CSMACD = 7 IfTypeISO88023CSMACD IfType = 7
IfTypeISO88024Tokenbus = 8 IfTypeISO88024Tokenbus IfType = 8
IfTypeISO88025Tokenring = 9 IfTypeISO88025Tokenring IfType = 9
IfTypeISO88026Man = 10 IfTypeISO88026Man IfType = 10
IfTypeStarlan = 11 IfTypeStarlan IfType = 11
IfTypeProteon10Mbit = 12 IfTypeProteon10Mbit IfType = 12
IfTypeProteon80Mbit = 13 IfTypeProteon80Mbit IfType = 13
IfTypeHyperchannel = 14 IfTypeHyperchannel IfType = 14
IfTypeFddi = 15 IfTypeFddi IfType = 15
IfTypeLapB = 16 IfTypeLapB IfType = 16
IfTypeSdlc = 17 IfTypeSdlc IfType = 17
IfTypeDs1 = 18 // DS1-MIB IfTypeDs1 IfType = 18 // DS1-MIB
IfTypeE1 = 19 // Obsolete; see DS1-MIB IfTypeE1 IfType = 19 // Obsolete; see DS1-MIB
IfTypeBasicISDN = 20 IfTypeBasicISDN IfType = 20
IfTypePrimaryISDN = 21 IfTypePrimaryISDN IfType = 21
IfTypePropPoint2PointSerial = 22 // proprietary serial IfTypePropPoint2PointSerial IfType = 22 // proprietary serial
IfTypePPP = 23 IfTypePPP IfType = 23
IfTypeSoftwareLoopback = 24 IfTypeSoftwareLoopback IfType = 24
IfTypeEon = 25 // CLNP over IP IfTypeEon IfType = 25 // CLNP over IP
IfTypeEthernet3Mbit = 26 IfTypeEthernet3Mbit IfType = 26
IfTypeNsip = 27 // XNS over IP IfTypeNsip IfType = 27 // XNS over IP
IfTypeSlip = 28 // Generic Slip IfTypeSlip IfType = 28 // Generic Slip
IfTypeUltra = 29 // ULTRA Technologies IfTypeUltra IfType = 29 // ULTRA Technologies
IfTypeDs3 = 30 // DS3-MIB IfTypeDs3 IfType = 30 // DS3-MIB
IfTypeSip = 31 // SMDS, coffee IfTypeSip IfType = 31 // SMDS, coffee
IfTypeFramerelay = 32 // DTE only IfTypeFramerelay IfType = 32 // DTE only
IfTypeRs232 = 33 IfTypeRs232 IfType = 33
IfTypePara = 34 // Parallel port IfTypePara IfType = 34 // Parallel port
IfTypeArcnet = 35 IfTypeArcnet IfType = 35
IfTypeArcnetPlus = 36 IfTypeArcnetPlus IfType = 36
IfTypeAtm = 37 // ATM cells IfTypeAtm IfType = 37 // ATM cells
IfTypeMioX25 = 38 IfTypeMioX25 IfType = 38
IfTypeSonet = 39 // SONET or SDH IfTypeSonet IfType = 39 // SONET or SDH
IfTypeX25Ple = 40 IfTypeX25Ple IfType = 40
IfTypeIso88022LLC = 41 IfTypeIso88022LLC IfType = 41
IfTypeLocaltalk = 42 IfTypeLocaltalk IfType = 42
IfTypeSmdsDxi = 43 IfTypeSmdsDxi IfType = 43
IfTypeFramerelayService = 44 // FRNETSERV-MIB IfTypeFramerelayService IfType = 44 // FRNETSERV-MIB
IfTypeV35 = 45 IfTypeV35 IfType = 45
IfTypeHssi = 46 IfTypeHssi IfType = 46
IfTypeHippi = 47 IfTypeHippi IfType = 47
IfTypeModem = 48 // Generic Modem IfTypeModem IfType = 48 // Generic Modem
IfTypeAal5 = 49 // AAL5 over ATM IfTypeAal5 IfType = 49 // AAL5 over ATM
IfTypeSonetPath = 50 IfTypeSonetPath IfType = 50
IfTypeSonetVt = 51 IfTypeSonetVt IfType = 51
IfTypeSmdsIcip = 52 // SMDS InterCarrier Interface IfTypeSmdsIcip IfType = 52 // SMDS InterCarrier Interface
IfTypePropVirtual = 53 // Proprietary virtual/internal IfTypePropVirtual IfType = 53 // Proprietary virtual/internal
IfTypePropMultiplexor = 54 // Proprietary multiplexing IfTypePropMultiplexor IfType = 54 // Proprietary multiplexing
IfTypeIEEE80212 = 55 // 100BaseVG IfTypeIEEE80212 IfType = 55 // 100BaseVG
IfTypeFibrechannel = 56 IfTypeFibrechannel IfType = 56
IfTypeHippiinterface = 57 IfTypeHippiinterface IfType = 57
IfTypeFramerelayInterconnect = 58 // Obsolete, use 32 or 44 IfTypeFramerelayInterconnect IfType = 58 // Obsolete, use 32 or 44
IfTypeAflane8023 = 59 // ATM Emulated LAN for 802.3 IfTypeAflane8023 IfType = 59 // ATM Emulated LAN for 802.3
IfTypeAflane8025 = 60 // ATM Emulated LAN for 802.5 IfTypeAflane8025 IfType = 60 // ATM Emulated LAN for 802.5
IfTypeCctemul = 61 // ATM Emulated circuit IfTypeCctemul IfType = 61 // ATM Emulated circuit
IfTypeFastether = 62 // Fast Ethernet (100BaseT) IfTypeFastether IfType = 62 // Fast Ethernet (100BaseT)
IfTypeISDN = 63 // ISDN and X.25 IfTypeISDN IfType = 63 // ISDN and X.25
IfTypeV11 = 64 // CCITT V.11/X.21 IfTypeV11 IfType = 64 // CCITT V.11/X.21
IfTypeV36 = 65 // CCITT V.36 IfTypeV36 IfType = 65 // CCITT V.36
IfTypeG703_64k = 66 // CCITT G703 at 64Kbps IfTypeG703_64k IfType = 66 // CCITT G703 at 64Kbps
IfTypeG703_2mb = 67 // Obsolete; see DS1-MIB IfTypeG703_2mb IfType = 67 // Obsolete; see DS1-MIB
IfTypeQllc = 68 // SNA QLLC IfTypeQllc IfType = 68 // SNA QLLC
IfTypeFastetherFX = 69 // Fast Ethernet (100BaseFX) IfTypeFastetherFX IfType = 69 // Fast Ethernet (100BaseFX)
IfTypeChannel = 70 IfTypeChannel IfType = 70
IfTypeIEEE80211 = 71 // Radio spread spectrum IfTypeIEEE80211 IfType = 71 // Radio spread spectrum
IfTypeIBM370parchan = 72 // IBM System 360/370 OEMI Channel IfTypeIBM370parchan IfType = 72 // IBM System 360/370 OEMI Channel
IfTypeEscon = 73 // IBM Enterprise Systems Connection IfTypeEscon IfType = 73 // IBM Enterprise Systems Connection
IfTypeDlsw = 74 // Data Link Switching IfTypeDlsw IfType = 74 // Data Link Switching
IfTypeISDNS = 75 // ISDN S/T interface IfTypeISDNS IfType = 75 // ISDN S/T interface
IfTypeISDNU = 76 // ISDN U interface IfTypeISDNU IfType = 76 // ISDN U interface
IfTypeLapD = 77 // Link Access Protocol D IfTypeLapD IfType = 77 // Link Access Protocol D
IfTypeIpswitch = 78 // IP Switching Objects IfTypeIpswitch IfType = 78 // IP Switching Objects
IfTypeRsrb = 79 // Remote Source Route Bridging IfTypeRsrb IfType = 79 // Remote Source Route Bridging
IfTypeAtmLogical = 80 // ATM Logical Port IfTypeAtmLogical IfType = 80 // ATM Logical Port
IfTypeDs0 = 81 // Digital Signal Level 0 IfTypeDs0 IfType = 81 // Digital Signal Level 0
IfTypeDs0Bundle = 82 // Group of ds0s on the same ds1 IfTypeDs0Bundle IfType = 82 // Group of ds0s on the same ds1
IfTypeBsc = 83 // Bisynchronous Protocol IfTypeBsc IfType = 83 // Bisynchronous Protocol
IfTypeAsync = 84 // Asynchronous Protocol IfTypeAsync IfType = 84 // Asynchronous Protocol
IfTypeCnr = 85 // Combat Net Radio IfTypeCnr IfType = 85 // Combat Net Radio
IfTypeIso88025rDtr = 86 // ISO 802.5r DTR IfTypeIso88025rDtr IfType = 86 // ISO 802.5r DTR
IfTypeEplrs = 87 // Ext Pos Loc Report Sys IfTypeEplrs IfType = 87 // Ext Pos Loc Report Sys
IfTypeArap = 88 // Appletalk Remote Access Protocol IfTypeArap IfType = 88 // Appletalk Remote Access Protocol
IfTypePropCnls = 89 // Proprietary Connectionless Proto IfTypePropCnls IfType = 89 // Proprietary Connectionless Proto
IfTypeHostpad = 90 // CCITT-ITU X.29 PAD Protocol IfTypeHostpad IfType = 90 // CCITT-ITU X.29 PAD Protocol
IfTypeTermpad = 91 // CCITT-ITU X.3 PAD Facility IfTypeTermpad IfType = 91 // CCITT-ITU X.3 PAD Facility
IfTypeFramerelayMpi = 92 // Multiproto Interconnect over FR IfTypeFramerelayMpi IfType = 92 // Multiproto Interconnect over FR
IfTypeX213 = 93 // CCITT-ITU X213 IfTypeX213 IfType = 93 // CCITT-ITU X213
IfTypeAdsl = 94 // Asymmetric Digital Subscrbr Loop IfTypeAdsl IfType = 94 // Asymmetric Digital Subscrbr Loop
IfTypeRadsl = 95 // Rate-Adapt Digital Subscrbr Loop IfTypeRadsl IfType = 95 // Rate-Adapt Digital Subscrbr Loop
IfTypeSdsl = 96 // Symmetric Digital Subscriber Loop IfTypeSdsl IfType = 96 // Symmetric Digital Subscriber Loop
IfTypeVdsl = 97 // Very H-Speed Digital Subscrb Loop IfTypeVdsl IfType = 97 // Very H-Speed Digital Subscrb Loop
IfTypeIso88025Crfprint = 98 // ISO 802.5 CRFP IfTypeIso88025Crfprint IfType = 98 // ISO 802.5 CRFP
IfTypeMyrinet = 99 // Myricom Myrinet IfTypeMyrinet IfType = 99 // Myricom Myrinet
IfTypeVoiceEm = 100 // Voice recEive and transMit IfTypeVoiceEm IfType = 100 // Voice recEive and transMit
IfTypeVoiceFxo = 101 // Voice Foreign Exchange Office IfTypeVoiceFxo IfType = 101 // Voice Foreign Exchange Office
IfTypeVoiceFxs = 102 // Voice Foreign Exchange Station IfTypeVoiceFxs IfType = 102 // Voice Foreign Exchange Station
IfTypeVoiceEncap = 103 // Voice encapsulation IfTypeVoiceEncap IfType = 103 // Voice encapsulation
IfTypeVoiceOverip = 104 // Voice over IP encapsulation IfTypeVoiceOverip IfType = 104 // Voice over IP encapsulation
IfTypeAtmDxi = 105 // ATM DXI IfTypeAtmDxi IfType = 105 // ATM DXI
IfTypeAtmFuni = 106 // ATM FUNI IfTypeAtmFuni IfType = 106 // ATM FUNI
IfTypeAtmIma = 107 // ATM IMA IfTypeAtmIma IfType = 107 // ATM IMA
IfTypePPPmultilinkbundle = 108 // PPP Multilink Bundle IfTypePPPmultilinkbundle IfType = 108 // PPP Multilink Bundle
IfTypeIpoverCdlc = 109 // IBM ipOverCdlc IfTypeIpoverCdlc IfType = 109 // IBM ipOverCdlc
IfTypeIpoverClaw = 110 // IBM Common Link Access to Workstn IfTypeIpoverClaw IfType = 110 // IBM Common Link Access to Workstn
IfTypeStacktostack = 111 // IBM stackToStack IfTypeStacktostack IfType = 111 // IBM stackToStack
IfTypeVirtualipaddress = 112 // IBM VIPA IfTypeVirtualipaddress IfType = 112 // IBM VIPA
IfTypeMpc = 113 // IBM multi-proto channel support IfTypeMpc IfType = 113 // IBM multi-proto channel support
IfTypeIpoverAtm = 114 // IBM ipOverAtm IfTypeIpoverAtm IfType = 114 // IBM ipOverAtm
IfTypeIso88025Fiber = 115 // ISO 802.5j Fiber Token Ring IfTypeIso88025Fiber IfType = 115 // ISO 802.5j Fiber Token Ring
IfTypeTdlc = 116 // IBM twinaxial data link control IfTypeTdlc IfType = 116 // IBM twinaxial data link control
IfTypeGigabitethernet = 117 IfTypeGigabitethernet IfType = 117
IfTypeHdlc = 118 IfTypeHdlc IfType = 118
IfTypeLapF = 119 IfTypeLapF IfType = 119
IfTypeV37 = 120 IfTypeV37 IfType = 120
IfTypeX25Mlp = 121 // Multi-Link Protocol IfTypeX25Mlp IfType = 121 // Multi-Link Protocol
IfTypeX25Huntgroup = 122 // X.25 Hunt Group IfTypeX25Huntgroup IfType = 122 // X.25 Hunt Group
IfTypeTransphdlc = 123 IfTypeTransphdlc IfType = 123
IfTypeInterleave = 124 // Interleave channel IfTypeInterleave IfType = 124 // Interleave channel
IfTypeFast = 125 // Fast channel IfTypeFast IfType = 125 // Fast channel
IfTypeIP = 126 // IP (for APPN HPR in IP networks) IfTypeIP IfType = 126 // IP (for APPN HPR in IP networks)
IfTypeDocscableMaclayer = 127 // CATV Mac Layer IfTypeDocscableMaclayer IfType = 127 // CATV Mac Layer
IfTypeDocscableDownstream = 128 // CATV Downstream interface IfTypeDocscableDownstream IfType = 128 // CATV Downstream interface
IfTypeDocscableUpstream = 129 // CATV Upstream interface IfTypeDocscableUpstream IfType = 129 // CATV Upstream interface
IfTypeA12mppswitch = 130 // Avalon Parallel Processor IfTypeA12mppswitch IfType = 130 // Avalon Parallel Processor
IfTypeTunnel = 131 // Encapsulation interface IfTypeTunnel IfType = 131 // Encapsulation interface
IfTypeCoffee = 132 // Coffee pot IfTypeCoffee IfType = 132 // Coffee pot
IfTypeCes = 133 // Circuit Emulation Service IfTypeCes IfType = 133 // Circuit Emulation Service
IfTypeAtmSubinterface = 134 // ATM Sub Interface IfTypeAtmSubinterface IfType = 134 // ATM Sub Interface
IfTypeL2Vlan = 135 // Layer 2 Virtual LAN using 802.1Q IfTypeL2Vlan IfType = 135 // Layer 2 Virtual LAN using 802.1Q
IfTypeL3Ipvlan = 136 // Layer 3 Virtual LAN using IP IfTypeL3Ipvlan IfType = 136 // Layer 3 Virtual LAN using IP
IfTypeL3Ipxvlan = 137 // Layer 3 Virtual LAN using IPX IfTypeL3Ipxvlan IfType = 137 // Layer 3 Virtual LAN using IPX
IfTypeDigitalpowerline = 138 // IP over Power Lines IfTypeDigitalpowerline IfType = 138 // IP over Power Lines
IfTypeMediamailoverip = 139 // Multimedia Mail over IP IfTypeMediamailoverip IfType = 139 // Multimedia Mail over IP
IfTypeDtm = 140 // Dynamic syncronous Transfer Mode IfTypeDtm IfType = 140 // Dynamic syncronous Transfer Mode
IfTypeDcn = 141 // Data Communications Network IfTypeDcn IfType = 141 // Data Communications Network
IfTypeIpforward = 142 // IP Forwarding Interface IfTypeIpforward IfType = 142 // IP Forwarding Interface
IfTypeMsdsl = 143 // Multi-rate Symmetric DSL IfTypeMsdsl IfType = 143 // Multi-rate Symmetric DSL
IfTypeIEEE1394 = 144 // IEEE1394 High Perf Serial Bus IfTypeIEEE1394 IfType = 144 // IEEE1394 High Perf Serial Bus
IfTypeIfGsn = 145 IfTypeIfGsn IfType = 145
IfTypeDvbrccMaclayer = 146 IfTypeDvbrccMaclayer IfType = 146
IfTypeDvbrccDownstream = 147 IfTypeDvbrccDownstream IfType = 147
IfTypeDvbrccUpstream = 148 IfTypeDvbrccUpstream IfType = 148
IfTypeAtmVirtual = 149 IfTypeAtmVirtual IfType = 149
IfTypeMplsTunnel = 150 IfTypeMplsTunnel IfType = 150
IfTypeSrp = 151 IfTypeSrp IfType = 151
IfTypeVoiceoveratm = 152 IfTypeVoiceoveratm IfType = 152
IfTypeVoiceoverframerelay = 153 IfTypeVoiceoverframerelay IfType = 153
IfTypeIdsl = 154 IfTypeIdsl IfType = 154
IfTypeCompositelink = 155 IfTypeCompositelink IfType = 155
IfTypeSs7Siglink = 156 IfTypeSs7Siglink IfType = 156
IfTypePropWirelessP2P = 157 IfTypePropWirelessP2P IfType = 157
IfTypeFrForward = 158 IfTypeFrForward IfType = 158
IfTypeRfc1483 = 159 IfTypeRfc1483 IfType = 159
IfTypeUsb = 160 IfTypeUsb IfType = 160
IfTypeIEEE8023adLag = 161 IfTypeIEEE8023adLag IfType = 161
IfTypeBgpPolicyAccounting = 162 IfTypeBgpPolicyAccounting IfType = 162
IfTypeFrf16MfrBundle = 163 IfTypeFrf16MfrBundle IfType = 163
IfTypeH323Gatekeeper = 164 IfTypeH323Gatekeeper IfType = 164
IfTypeH323Proxy = 165 IfTypeH323Proxy IfType = 165
IfTypeMpls = 166 IfTypeMpls IfType = 166
IfTypeMfSiglink = 167 IfTypeMfSiglink IfType = 167
IfTypeHdsl2 = 168 IfTypeHdsl2 IfType = 168
IfTypeShdsl = 169 IfTypeShdsl IfType = 169
IfTypeDs1Fdl = 170 IfTypeDs1Fdl IfType = 170
IfTypePos = 171 IfTypePos IfType = 171
IfTypeDvbAsiIn = 172 IfTypeDvbAsiIn IfType = 172
IfTypeDvbAsiOut = 173 IfTypeDvbAsiOut IfType = 173
IfTypePlc = 174 IfTypePlc IfType = 174
IfTypeNfas = 175 IfTypeNfas IfType = 175
IfTypeTr008 = 176 IfTypeTr008 IfType = 176
IfTypeGr303Rdt = 177 IfTypeGr303Rdt IfType = 177
IfTypeGr303Idt = 178 IfTypeGr303Idt IfType = 178
IfTypeIsup = 179 IfTypeIsup IfType = 179
IfTypePropDocsWirelessMaclayer = 180 IfTypePropDocsWirelessMaclayer IfType = 180
IfTypePropDocsWirelessDownstream = 181 IfTypePropDocsWirelessDownstream IfType = 181
IfTypePropDocsWirelessUpstream = 182 IfTypePropDocsWirelessUpstream IfType = 182
IfTypeHiperlan2 = 183 IfTypeHiperlan2 IfType = 183
IfTypePropBwaP2MP = 184 IfTypePropBwaP2MP IfType = 184
IfTypeSonetOverheadChannel = 185 IfTypeSonetOverheadChannel IfType = 185
IfTypeDigitalWrapperOverheadChannel = 186 IfTypeDigitalWrapperOverheadChannel IfType = 186
IfTypeAal2 = 187 IfTypeAal2 IfType = 187
IfTypeRadioMac = 188 IfTypeRadioMac IfType = 188
IfTypeAtmRadio = 189 IfTypeAtmRadio IfType = 189
IfTypeImt = 190 IfTypeImt IfType = 190
IfTypeMvl = 191 IfTypeMvl IfType = 191
IfTypeReachDsl = 192 IfTypeReachDsl IfType = 192
IfTypeFrDlciEndpt = 193 IfTypeFrDlciEndpt IfType = 193
IfTypeAtmVciEndpt = 194 IfTypeAtmVciEndpt IfType = 194
IfTypeOpticalChannel = 195 IfTypeOpticalChannel IfType = 195
IfTypeOpticalTransport = 196 IfTypeOpticalTransport IfType = 196
IfTypeIEEE80216Wman = 237 IfTypeIEEE80216Wman IfType = 237
IfTypeWwanpp = 243 // WWAN devices based on GSM technology IfTypeWwanpp IfType = 243 // WWAN devices based on GSM technology
IfTypeWwanpp2 = 244 // WWAN devices based on CDMA technology IfTypeWwanpp2 IfType = 244 // WWAN devices based on CDMA technology
IfTypeIEEE802154 = 259 // IEEE 802.15.4 WPAN interface IfTypeIEEE802154 IfType = 259 // IEEE 802.15.4 WPAN interface
IfTypeXboxWireless = 281 IfTypeXboxWireless IfType = 281
) )
// MibIfEntryLevel enumeration specifies level of interface information to retrieve in GetIfTable2Ex function call. // MibIfEntryLevel enumeration specifies level of interface information to retrieve in GetIfTable2Ex function call.
@ -270,7 +272,7 @@ type MibIfEntryLevel uint32
const ( const (
MibIfEntryNormal MibIfEntryLevel = 0 MibIfEntryNormal MibIfEntryLevel = 0
MibIfEntryNormalWithoutStatistics = 2 MibIfEntryNormalWithoutStatistics MibIfEntryLevel = 2
) )
// NdisMedium enumeration type identifies the medium types that NDIS drivers support. // NdisMedium enumeration type identifies the medium types that NDIS drivers support.
@ -522,12 +524,12 @@ type TunnelType uint32
const ( const (
TunnelTypeNone TunnelType = 0 TunnelTypeNone TunnelType = 0
TunnelTypeOther = 1 TunnelTypeOther TunnelType = 1
TunnelTypeDirect = 2 TunnelTypeDirect TunnelType = 2
TunnelType6to4 = 11 TunnelType6to4 TunnelType = 11
TunnelTypeIsatap = 13 TunnelTypeIsatap TunnelType = 13
TunnelTypeTeredo = 14 TunnelTypeTeredo TunnelType = 14
TunnelTypeIPHTTPS = 15 TunnelTypeIPHTTPS TunnelType = 15
) )
// InterfaceAndOperStatusFlags enumeration type defines interface and operation flags // InterfaceAndOperStatusFlags enumeration type defines interface and operation flags
@ -574,13 +576,13 @@ type ScopeLevel uint32
const ( const (
ScopeLevelInterface ScopeLevel = 1 ScopeLevelInterface ScopeLevel = 1
ScopeLevelLink = 2 ScopeLevelLink ScopeLevel = 2
ScopeLevelSubnet = 3 ScopeLevelSubnet ScopeLevel = 3
ScopeLevelAdmin = 4 ScopeLevelAdmin ScopeLevel = 4
ScopeLevelSite = 5 ScopeLevelSite ScopeLevel = 5
ScopeLevelOrganization = 8 ScopeLevelOrganization ScopeLevel = 8
ScopeLevelGlobal = 14 ScopeLevelGlobal ScopeLevel = 14
ScopeLevelCount = 16 ScopeLevelCount ScopeLevel = 16
) )
// RouteData structure describes a route to add // RouteData structure describes a route to add
@ -757,7 +759,7 @@ func (addr *RawSockaddrInet) SetAddrPort(addrPort netip.AddrPort) error {
addr4.Family = windows.AF_INET addr4.Family = windows.AF_INET
addr4.Addr = addrPort.Addr().As4() addr4.Addr = addrPort.Addr().As4()
addr4.Port = htons(addrPort.Port()) addr4.Port = htons(addrPort.Port())
for i := 0; i < 8; i++ { for i := range 8 {
addr4.Zero[i] = 0 addr4.Zero[i] = 0
} }
return nil return nil

View file

@ -1,4 +1,4 @@
//go:build 386 || arm //go:build windows && (386 || arm)
/* SPDX-License-Identifier: MIT /* SPDX-License-Identifier: MIT
* *

View file

@ -1,4 +1,4 @@
//go:build amd64 || arm64 //go:build windows && (amd64 || arm64)
/* SPDX-License-Identifier: MIT /* SPDX-License-Identifier: MIT
* *

View file

@ -1,3 +1,5 @@
//go:build windows
/* SPDX-License-Identifier: MIT /* SPDX-License-Identifier: MIT
* *
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved. * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.

View file

@ -1,4 +1,4 @@
//go:build 386 || arm //go:build windows && (386 || arm)
/* SPDX-License-Identifier: MIT /* SPDX-License-Identifier: MIT
* *

View file

@ -1,4 +1,4 @@
//go:build amd64 || arm64 //go:build windows && (amd64 || arm64)
/* SPDX-License-Identifier: MIT /* SPDX-License-Identifier: MIT
* *

View file

@ -1,3 +1,5 @@
//go:build windows
/* SPDX-License-Identifier: MIT /* SPDX-License-Identifier: MIT
* *
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved. * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.

View file

@ -1,3 +1,5 @@
//go:build windows
/* SPDX-License-Identifier: MIT /* SPDX-License-Identifier: MIT
* *
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved. * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.

View file

@ -1,3 +1,5 @@
//go:build windows
/* SPDX-License-Identifier: MIT /* SPDX-License-Identifier: MIT
* *
* Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved. * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
@ -104,6 +106,9 @@ func TestAdaptersAddresses(t *testing.T) {
} }
ifcs, err = GetAdaptersAddresses(windows.AF_UNSPEC, GAAFlagDefault) ifcs, err = GetAdaptersAddresses(windows.AF_UNSPEC, GAAFlagDefault)
if err != nil {
t.Errorf("GetAdaptersAddresses() returned error: %v", err)
}
for _, i := range ifcs { for _, i := range ifcs {
ifc, err := i.LUID.Interface() ifc, err := i.LUID.Interface()
@ -370,7 +375,7 @@ func TestAddDeleteIPAddress(t *testing.T) {
return return
} }
addr, err := ifc.LUID.IPAddress(nonexistantIPv4ToAdd.Addr()) _, err = ifc.LUID.IPAddress(nonexistantIPv4ToAdd.Addr())
if err == nil { if err == nil {
t.Errorf("Unicast address %s already exists. Please set nonexistantIPv4ToAdd appropriately.", nonexistantIPv4ToAdd.Addr().String()) t.Errorf("Unicast address %s already exists. Please set nonexistantIPv4ToAdd appropriately.", nonexistantIPv4ToAdd.Addr().String())
return return
@ -414,7 +419,7 @@ func TestAddDeleteIPAddress(t *testing.T) {
if count != 1 { if count != 1 {
t.Errorf("After adding there are %d new interface(s).", count) t.Errorf("After adding there are %d new interface(s).", count)
} }
addr, err = ifc.LUID.IPAddress(nonexistantIPv4ToAdd.Addr()) addr, err := ifc.LUID.IPAddress(nonexistantIPv4ToAdd.Addr())
if err != nil { if err != nil {
t.Errorf("LUID.IPAddress() returned an error: %w", err) t.Errorf("LUID.IPAddress() returned an error: %w", err)
} else if addr == nil { } else if addr == nil {
@ -431,7 +436,7 @@ func TestAddDeleteIPAddress(t *testing.T) {
time.Sleep(500 * time.Millisecond) time.Sleep(500 * time.Millisecond)
addr, err = ifc.LUID.IPAddress(nonexistantIPv4ToAdd.Addr()) _, err = ifc.LUID.IPAddress(nonexistantIPv4ToAdd.Addr())
if err == nil { if err == nil {
t.Errorf("Unicast address %s still exists, although it's deleted successfully.", nonexistantIPv4ToAdd.Addr().String()) t.Errorf("Unicast address %s still exists, although it's deleted successfully.", nonexistantIPv4ToAdd.Addr().String())
} else if err != windows.ERROR_NOT_FOUND { } else if err != windows.ERROR_NOT_FOUND {

View file

@ -56,16 +56,16 @@ func (module *Module) copySections(address, size uintptr, oldHeaders *IMAGE_NT_H
if sectionSize == 0 { if sectionSize == 0 {
continue continue
} }
dest, err := windows.VirtualAlloc(module.codeBase+uintptr(sections[i].VirtualAddress), _, err := windows.VirtualAlloc(module.codeBase+uintptr(sections[i].VirtualAddress),
uintptr(sectionSize), uintptr(sectionSize),
windows.MEM_COMMIT, windows.MEM_COMMIT,
windows.PAGE_READWRITE) windows.PAGE_READWRITE)
if err != nil { if err != nil {
return fmt.Errorf("Error allocating section: %w", err) return fmt.Errorf("error allocating section: %w", err)
} }
// Always use position from file to support alignments smaller than page size (allocation above will align to page size). // Always use position from file to support alignments smaller than page size (allocation above will align to page size).
dest = module.codeBase + uintptr(sections[i].VirtualAddress) dest := module.codeBase + uintptr(sections[i].VirtualAddress)
// NOTE: On 64bit systems we truncate to 32bit here but expand again later when "PhysicalAddress" is used. // NOTE: On 64bit systems we truncate to 32bit here but expand again later when "PhysicalAddress" is used.
sections[i].SetPhysicalAddress((uint32)(dest & 0xffffffff)) sections[i].SetPhysicalAddress((uint32)(dest & 0xffffffff))
dst := unsafe.Slice((*byte)(a2p(dest)), sectionSize) dst := unsafe.Slice((*byte)(a2p(dest)), sectionSize)
@ -76,7 +76,7 @@ func (module *Module) copySections(address, size uintptr, oldHeaders *IMAGE_NT_H
} }
if size < uintptr(sections[i].PointerToRawData)+uintptr(sections[i].SizeOfRawData) { if size < uintptr(sections[i].PointerToRawData)+uintptr(sections[i].SizeOfRawData) {
return errors.New("Incomplete section") return errors.New("incomplete section")
} }
// Commit memory block and copy data from dll. // Commit memory block and copy data from dll.
@ -85,7 +85,7 @@ func (module *Module) copySections(address, size uintptr, oldHeaders *IMAGE_NT_H
windows.MEM_COMMIT, windows.MEM_COMMIT,
windows.PAGE_READWRITE) windows.PAGE_READWRITE)
if err != nil { if err != nil {
return fmt.Errorf("Error allocating memory block: %w", err) return fmt.Errorf("error allocating memory block: %w", err)
} }
// Always use position from file to support alignments smaller than page size (allocation above will align to page size). // Always use position from file to support alignments smaller than page size (allocation above will align to page size).
@ -158,7 +158,7 @@ func (module *Module) finalizeSection(sectionData *sectionFinalizeData) error {
var oldProtect uint32 var oldProtect uint32
err := windows.VirtualProtect(sectionData.address, sectionData.size, protect, &oldProtect) err := windows.VirtualProtect(sectionData.address, sectionData.size, protect, &oldProtect)
if err != nil { if err != nil {
return fmt.Errorf("Error protecting memory page: %w", err) return fmt.Errorf("error protecting memory page: %w", err)
} }
return nil return nil
@ -204,7 +204,7 @@ func (module *Module) finalizeSections() error {
err := module.finalizeSection(&sectionData) err := module.finalizeSection(&sectionData)
if err != nil { if err != nil {
return fmt.Errorf("Error finalizing section: %w", err) return fmt.Errorf("error finalizing section: %w", err)
} }
sectionData.address = sectionAddress sectionData.address = sectionAddress
sectionData.alignedAddress = alignedAddress sectionData.alignedAddress = alignedAddress
@ -214,7 +214,7 @@ func (module *Module) finalizeSections() error {
sectionData.last = true sectionData.last = true
err := module.finalizeSection(&sectionData) err := module.finalizeSection(&sectionData)
if err != nil { if err != nil {
return fmt.Errorf("Error finalizing section: %w", err) return fmt.Errorf("error finalizing section: %w", err)
} }
return nil return nil
} }
@ -250,10 +250,10 @@ func (module *Module) performBaseRelocation(delta uintptr) (relocated bool, err
relocationHdr := (*IMAGE_BASE_RELOCATION)(a2p(relocBase)) relocationHdr := (*IMAGE_BASE_RELOCATION)(a2p(relocBase))
for uintptr(unsafe.Pointer(relocationHdr))+unsafe.Sizeof(*relocationHdr) <= relocEnd && relocationHdr.VirtualAddress > 0 { for uintptr(unsafe.Pointer(relocationHdr))+unsafe.Sizeof(*relocationHdr) <= relocEnd && relocationHdr.VirtualAddress > 0 {
if uintptr(relocationHdr.SizeOfBlock) < unsafe.Sizeof(*relocationHdr) { if uintptr(relocationHdr.SizeOfBlock) < unsafe.Sizeof(*relocationHdr) {
return false, errors.New("Invalid relocation block size") return false, errors.New("invalid relocation block size")
} }
if uintptr(unsafe.Pointer(relocationHdr))+uintptr(relocationHdr.SizeOfBlock) > relocEnd { if uintptr(unsafe.Pointer(relocationHdr))+uintptr(relocationHdr.SizeOfBlock) > relocEnd {
return false, errors.New("Relocation block exceeds directory bounds") return false, errors.New("relocation block exceeds directory bounds")
} }
dest := module.codeBase + uintptr(relocationHdr.VirtualAddress) dest := module.codeBase + uintptr(relocationHdr.VirtualAddress)
@ -272,11 +272,9 @@ func (module *Module) performBaseRelocation(delta uintptr) (relocated bool, err
case IMAGE_REL_BASED_LOW: case IMAGE_REL_BASED_LOW:
*(*uint16)(a2p(dest + relOffset)) += uint16(delta & 0xffff) *(*uint16)(a2p(dest + relOffset)) += uint16(delta & 0xffff)
break
case IMAGE_REL_BASED_HIGH: case IMAGE_REL_BASED_HIGH:
*(*uint16)(a2p(dest + relOffset)) += uint16(uint32(delta) >> 16) *(*uint16)(a2p(dest + relOffset)) += uint16(uint32(delta) >> 16)
break
case IMAGE_REL_BASED_HIGHLOW: case IMAGE_REL_BASED_HIGHLOW:
*(*uint32)(a2p(dest + relOffset)) += uint32(delta) *(*uint32)(a2p(dest + relOffset)) += uint32(delta)
@ -289,7 +287,7 @@ func (module *Module) performBaseRelocation(delta uintptr) (relocated bool, err
imm16 := ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) + imm16 := ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) +
((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff) ((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff)
if (inst & 0x8000fbf0) != 0x0000f240 { if (inst & 0x8000fbf0) != 0x0000f240 {
return false, fmt.Errorf("Wrong Thumb2 instruction %08x, expected MOVW", inst) return false, fmt.Errorf("wrong Thumb2 instruction %08x, expected MOVW", inst)
} }
imm16 += uint32(delta) & 0xffff imm16 += uint32(delta) & 0xffff
hiDelta := (uint32(delta&0xffff0000) >> 16) + ((imm16 & 0xffff0000) >> 16) hiDelta := (uint32(delta&0xffff0000) >> 16) + ((imm16 & 0xffff0000) >> 16)
@ -302,11 +300,11 @@ func (module *Module) performBaseRelocation(delta uintptr) (relocated bool, err
imm16 = ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) + imm16 = ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) +
((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff) ((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff)
if (inst & 0x8000fbf0) != 0x0000f2c0 { if (inst & 0x8000fbf0) != 0x0000f2c0 {
return false, fmt.Errorf("Wrong Thumb2 instruction %08x, expected MOVT", inst) return false, fmt.Errorf("wrong Thumb2 instruction %08x, expected MOVT", inst)
} }
imm16 += hiDelta imm16 += hiDelta
if imm16 > 0xffff { if imm16 > 0xffff {
return false, fmt.Errorf("Resulting immediate value won't fit: %08x", imm16) return false, fmt.Errorf("resulting immediate value won't fit: %08x", imm16)
} }
*(*uint32)(a2p(dest + relOffset + 4)) = (inst & 0x8f00fbf0) + *(*uint32)(a2p(dest + relOffset + 4)) = (inst & 0x8f00fbf0) +
((imm16 >> 1) & 0x0400) + ((imm16 >> 1) & 0x0400) +
@ -316,7 +314,7 @@ func (module *Module) performBaseRelocation(delta uintptr) (relocated bool, err
} }
default: default:
return false, fmt.Errorf("Unsupported relocation: %v", relType) return false, fmt.Errorf("unsupported relocation: %v", relType)
} }
} }
@ -337,7 +335,7 @@ func (module *Module) buildImportTable() error {
for importDesc.Name != 0 { for importDesc.Name != 0 {
handle, err := windows.LoadLibraryEx(windows.BytePtrToString((*byte)(a2p(module.codeBase+uintptr(importDesc.Name)))), 0, windows.LOAD_LIBRARY_SEARCH_SYSTEM32) handle, err := windows.LoadLibraryEx(windows.BytePtrToString((*byte)(a2p(module.codeBase+uintptr(importDesc.Name)))), 0, windows.LOAD_LIBRARY_SEARCH_SYSTEM32)
if err != nil { if err != nil {
return fmt.Errorf("Error loading module: %w", err) return fmt.Errorf("error loading module: %w", err)
} }
var thunkRef, funcRef *uintptr var thunkRef, funcRef *uintptr
if importDesc.OriginalFirstThunk() != 0 { if importDesc.OriginalFirstThunk() != 0 {
@ -357,7 +355,7 @@ func (module *Module) buildImportTable() error {
} }
if err != nil { if err != nil {
windows.FreeLibrary(handle) windows.FreeLibrary(handle)
return fmt.Errorf("Error getting function address: %w", err) return fmt.Errorf("error getting function address: %w", err)
} }
thunkRef = (*uintptr)(a2p(uintptr(unsafe.Pointer(thunkRef)) + unsafe.Sizeof(*thunkRef))) thunkRef = (*uintptr)(a2p(uintptr(unsafe.Pointer(thunkRef)) + unsafe.Sizeof(*thunkRef)))
funcRef = (*uintptr)(a2p(uintptr(unsafe.Pointer(funcRef)) + unsafe.Sizeof(*funcRef))) funcRef = (*uintptr)(a2p(uintptr(unsafe.Pointer(funcRef)) + unsafe.Sizeof(*funcRef)))
@ -371,14 +369,14 @@ func (module *Module) buildImportTable() error {
func (module *Module) buildNameExports() error { func (module *Module) buildNameExports() error {
directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT) directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT)
if directory.Size == 0 { if directory.Size == 0 {
return errors.New("No export table found") return errors.New("no export table found")
} }
exports := (*IMAGE_EXPORT_DIRECTORY)(a2p(module.codeBase + uintptr(directory.VirtualAddress))) exports := (*IMAGE_EXPORT_DIRECTORY)(a2p(module.codeBase + uintptr(directory.VirtualAddress)))
if exports.NumberOfNames == 0 || exports.NumberOfFunctions == 0 { if exports.NumberOfNames == 0 || exports.NumberOfFunctions == 0 {
return errors.New("No functions exported") return errors.New("no functions exported")
} }
if exports.NumberOfNames == 0 { if exports.NumberOfNames == 0 {
return errors.New("No functions exported by name") return errors.New("no functions exported by name")
} }
nameRefs := unsafe.Slice((*uint32)(a2p(module.codeBase+uintptr(exports.AddressOfNames))), exports.NumberOfNames) nameRefs := unsafe.Slice((*uint32)(a2p(module.codeBase+uintptr(exports.AddressOfNames))), exports.NumberOfNames)
ordinals := unsafe.Slice((*uint16)(a2p(module.codeBase+uintptr(exports.AddressOfNameOrdinals))), exports.NumberOfNames) ordinals := unsafe.Slice((*uint16)(a2p(module.codeBase+uintptr(exports.AddressOfNameOrdinals))), exports.NumberOfNames)
@ -466,39 +464,39 @@ func hookRtlPcToFileHeader() error {
func LoadLibrary(data []byte) (module *Module, err error) { func LoadLibrary(data []byte) (module *Module, err error) {
size := uintptr(len(data)) size := uintptr(len(data))
if size < unsafe.Sizeof(IMAGE_DOS_HEADER{}) { if size < unsafe.Sizeof(IMAGE_DOS_HEADER{}) {
return nil, errors.New("Incomplete IMAGE_DOS_HEADER") return nil, errors.New("incomplete IMAGE_DOS_HEADER")
} }
addr := uintptr(unsafe.Pointer(&data[0])) addr := uintptr(unsafe.Pointer(&data[0]))
dosHeader := (*IMAGE_DOS_HEADER)(a2p(addr)) dosHeader := (*IMAGE_DOS_HEADER)(a2p(addr))
if dosHeader.E_magic != IMAGE_DOS_SIGNATURE { if dosHeader.E_magic != IMAGE_DOS_SIGNATURE {
return nil, fmt.Errorf("Not an MS-DOS binary (provided: %x, expected: %x)", dosHeader.E_magic, IMAGE_DOS_SIGNATURE) return nil, fmt.Errorf("not an MS-DOS binary (provided: %x, expected: %x)", dosHeader.E_magic, IMAGE_DOS_SIGNATURE)
} }
if dosHeader.E_lfanew < 0 || (size < uintptr(dosHeader.E_lfanew)+unsafe.Sizeof(IMAGE_NT_HEADERS{})) { if dosHeader.E_lfanew < 0 || (size < uintptr(dosHeader.E_lfanew)+unsafe.Sizeof(IMAGE_NT_HEADERS{})) {
return nil, errors.New("Incomplete IMAGE_NT_HEADERS") return nil, errors.New("incomplete IMAGE_NT_HEADERS")
} }
oldHeader := (*IMAGE_NT_HEADERS)(a2p(addr + uintptr(dosHeader.E_lfanew))) oldHeader := (*IMAGE_NT_HEADERS)(a2p(addr + uintptr(dosHeader.E_lfanew)))
if oldHeader.Signature != IMAGE_NT_SIGNATURE { if oldHeader.Signature != IMAGE_NT_SIGNATURE {
return nil, fmt.Errorf("Not an NT binary (provided: %x, expected: %x)", oldHeader.Signature, IMAGE_NT_SIGNATURE) return nil, fmt.Errorf("not an NT binary (provided: %x, expected: %x)", oldHeader.Signature, IMAGE_NT_SIGNATURE)
} }
if oldHeader.FileHeader.Machine != imageFileProcess { if oldHeader.FileHeader.Machine != imageFileProcess {
return nil, fmt.Errorf("Foreign platform (provided: %x, expected: %x)", oldHeader.FileHeader.Machine, imageFileProcess) return nil, fmt.Errorf("foreign platform (provided: %x, expected: %x)", oldHeader.FileHeader.Machine, imageFileProcess)
} }
if oldHeader.OptionalHeader.SectionAlignment == 0 || (oldHeader.OptionalHeader.SectionAlignment&(oldHeader.OptionalHeader.SectionAlignment-1)) != 0 { if oldHeader.OptionalHeader.SectionAlignment == 0 || (oldHeader.OptionalHeader.SectionAlignment&(oldHeader.OptionalHeader.SectionAlignment-1)) != 0 {
return nil, errors.New("Unaligned section") return nil, errors.New("unaligned section")
} }
if oldHeader.FileHeader.NumberOfSections == 0 { if oldHeader.FileHeader.NumberOfSections == 0 {
return nil, errors.New("No sections") return nil, errors.New("no sections")
} }
if uintptr(oldHeader.FileHeader.SizeOfOptionalHeader) < unsafe.Sizeof(oldHeader.OptionalHeader) { if uintptr(oldHeader.FileHeader.SizeOfOptionalHeader) < unsafe.Sizeof(oldHeader.OptionalHeader) {
return nil, errors.New("Incomplete optional header") return nil, errors.New("incomplete optional header")
} }
if oldHeader.OptionalHeader.NumberOfRvaAndSizes < IMAGE_NUMBEROF_DIRECTORY_ENTRIES { if oldHeader.OptionalHeader.NumberOfRvaAndSizes < IMAGE_NUMBEROF_DIRECTORY_ENTRIES {
return nil, errors.New("Incomplete data directory") return nil, errors.New("incomplete data directory")
} }
sectionHeadersEnd := uintptr(dosHeader.E_lfanew) + unsafe.Offsetof(oldHeader.OptionalHeader) + uintptr(oldHeader.FileHeader.SizeOfOptionalHeader) + sectionHeadersEnd := uintptr(dosHeader.E_lfanew) + unsafe.Offsetof(oldHeader.OptionalHeader) + uintptr(oldHeader.FileHeader.SizeOfOptionalHeader) +
uintptr(oldHeader.FileHeader.NumberOfSections)*unsafe.Sizeof(IMAGE_SECTION_HEADER{}) uintptr(oldHeader.FileHeader.NumberOfSections)*unsafe.Sizeof(IMAGE_SECTION_HEADER{})
if size < sectionHeadersEnd { if size < sectionHeadersEnd {
return nil, errors.New("Incomplete section headers") return nil, errors.New("incomplete section headers")
} }
lastSectionEnd := uintptr(0) lastSectionEnd := uintptr(0)
sections := oldHeader.Sections() sections := oldHeader.Sections()
@ -517,7 +515,7 @@ func LoadLibrary(data []byte) (module *Module, err error) {
} }
alignedImageSize := alignUp(uintptr(oldHeader.OptionalHeader.SizeOfImage), uintptr(oldHeader.OptionalHeader.SectionAlignment)) alignedImageSize := alignUp(uintptr(oldHeader.OptionalHeader.SizeOfImage), uintptr(oldHeader.OptionalHeader.SectionAlignment))
if alignedImageSize != alignUp(lastSectionEnd, uintptr(oldHeader.OptionalHeader.SectionAlignment)) { if alignedImageSize != alignUp(lastSectionEnd, uintptr(oldHeader.OptionalHeader.SectionAlignment)) {
return nil, errors.New("Section is not page-aligned") return nil, errors.New("section is not page-aligned")
} }
module = &Module{isDLL: (oldHeader.FileHeader.Characteristics & IMAGE_FILE_DLL) != 0} module = &Module{isDLL: (oldHeader.FileHeader.Characteristics & IMAGE_FILE_DLL) != 0}
@ -541,18 +539,18 @@ func LoadLibrary(data []byte) (module *Module, err error) {
windows.MEM_RESERVE|windows.MEM_COMMIT, windows.MEM_RESERVE|windows.MEM_COMMIT,
windows.PAGE_READWRITE) windows.PAGE_READWRITE)
if err != nil { if err != nil {
err = fmt.Errorf("Error allocating code: %w", err) err = fmt.Errorf("error allocating code: %w", err)
return return
} }
} }
err = module.check4GBBoundaries(alignedImageSize) err = module.check4GBBoundaries(alignedImageSize)
if err != nil { if err != nil {
err = fmt.Errorf("Error reallocating code: %w", err) err = fmt.Errorf("error reallocating code: %w", err)
return return
} }
if size < uintptr(oldHeader.OptionalHeader.SizeOfHeaders) { if size < uintptr(oldHeader.OptionalHeader.SizeOfHeaders) {
err = errors.New("Incomplete headers") err = errors.New("incomplete headers")
return return
} }
// Commit memory for headers. // Commit memory for headers.
@ -561,7 +559,7 @@ func LoadLibrary(data []byte) (module *Module, err error) {
windows.MEM_COMMIT, windows.MEM_COMMIT,
windows.PAGE_READWRITE) windows.PAGE_READWRITE)
if err != nil { if err != nil {
err = fmt.Errorf("Error allocating headers: %w", err) err = fmt.Errorf("error allocating headers: %w", err)
return return
} }
// Copy PE header to code. // Copy PE header to code.
@ -574,7 +572,7 @@ func LoadLibrary(data []byte) (module *Module, err error) {
// Copy sections from DLL file block to new memory location. // Copy sections from DLL file block to new memory location.
err = module.copySections(addr, size, oldHeader) err = module.copySections(addr, size, oldHeader)
if err != nil { if err != nil {
err = fmt.Errorf("Error copying sections: %w", err) err = fmt.Errorf("error copying sections: %w", err)
return return
} }
@ -583,7 +581,7 @@ func LoadLibrary(data []byte) (module *Module, err error) {
if locationDelta != 0 { if locationDelta != 0 {
module.isRelocated, err = module.performBaseRelocation(locationDelta) module.isRelocated, err = module.performBaseRelocation(locationDelta)
if err != nil { if err != nil {
err = fmt.Errorf("Error relocating module: %w", err) err = fmt.Errorf("error relocating module: %w", err)
return return
} }
if !module.isRelocated { if !module.isRelocated {
@ -597,14 +595,14 @@ func LoadLibrary(data []byte) (module *Module, err error) {
// Load required dlls and adjust function table of imports. // Load required dlls and adjust function table of imports.
err = module.buildImportTable() err = module.buildImportTable()
if err != nil { if err != nil {
err = fmt.Errorf("Error building import table: %w", err) err = fmt.Errorf("error building import table: %w", err)
return return
} }
// Mark memory pages depending on section headers and release sections that are marked as "discardable". // Mark memory pages depending on section headers and release sections that are marked as "discardable".
err = module.finalizeSections() err = module.finalizeSections()
if err != nil { if err != nil {
err = fmt.Errorf("Error finalizing sections: %w", err) err = fmt.Errorf("error finalizing sections: %w", err)
return return
} }
@ -673,35 +671,35 @@ func (module *Module) Free() {
func (module *Module) ProcAddressByName(name string) (uintptr, error) { func (module *Module) ProcAddressByName(name string) (uintptr, error) {
directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT) directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT)
if directory.Size == 0 { if directory.Size == 0 {
return 0, errors.New("No export table found") return 0, errors.New("no export table found")
} }
exports := (*IMAGE_EXPORT_DIRECTORY)(a2p(module.codeBase + uintptr(directory.VirtualAddress))) exports := (*IMAGE_EXPORT_DIRECTORY)(a2p(module.codeBase + uintptr(directory.VirtualAddress)))
if module.nameExports == nil { if module.nameExports == nil {
return 0, errors.New("No functions exported by name") return 0, errors.New("no functions exported by name")
} }
if idx, ok := module.nameExports[name]; ok { if idx, ok := module.nameExports[name]; ok {
if uint32(idx) >= exports.NumberOfFunctions { if uint32(idx) >= exports.NumberOfFunctions {
return 0, errors.New("Ordinal number too high") return 0, errors.New("ordinal number too high")
} }
// AddressOfFunctions contains the RVAs to the "real" functions. // AddressOfFunctions contains the RVAs to the "real" functions.
return module.codeBase + uintptr(*(*uint32)(a2p(module.codeBase + uintptr(exports.AddressOfFunctions) + uintptr(idx)*4))), nil return module.codeBase + uintptr(*(*uint32)(a2p(module.codeBase + uintptr(exports.AddressOfFunctions) + uintptr(idx)*4))), nil
} }
return 0, errors.New("Function not found by name") return 0, errors.New("function not found by name")
} }
// ProcAddressByOrdinal returns function address by exported ordinal. // ProcAddressByOrdinal returns function address by exported ordinal.
func (module *Module) ProcAddressByOrdinal(ordinal uint16) (uintptr, error) { func (module *Module) ProcAddressByOrdinal(ordinal uint16) (uintptr, error) {
directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT) directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT)
if directory.Size == 0 { if directory.Size == 0 {
return 0, errors.New("No export table found") return 0, errors.New("no export table found")
} }
exports := (*IMAGE_EXPORT_DIRECTORY)(a2p(module.codeBase + uintptr(directory.VirtualAddress))) exports := (*IMAGE_EXPORT_DIRECTORY)(a2p(module.codeBase + uintptr(directory.VirtualAddress)))
if uint32(ordinal) < exports.Base { if uint32(ordinal) < exports.Base {
return 0, errors.New("Ordinal number too low") return 0, errors.New("ordinal number too low")
} }
idx := ordinal - uint16(exports.Base) idx := ordinal - uint16(exports.Base)
if uint32(idx) >= exports.NumberOfFunctions { if uint32(idx) >= exports.NumberOfFunctions {
return 0, errors.New("Ordinal number too high") return 0, errors.New("ordinal number too high")
} }
// AddressOfFunctions contains the RVAs to the "real" functions. // AddressOfFunctions contains the RVAs to the "real" functions.
return module.codeBase + uintptr(*(*uint32)(a2p(module.codeBase + uintptr(exports.AddressOfFunctions) + uintptr(idx)*4))), nil return module.codeBase + uintptr(*(*uint32)(a2p(module.codeBase + uintptr(exports.AddressOfFunctions) + uintptr(idx)*4))), nil

View file

@ -29,7 +29,7 @@ func (module *Module) check4GBBoundaries(alignedImageSize uintptr) (err error) {
windows.MEM_RESERVE|windows.MEM_COMMIT, windows.MEM_RESERVE|windows.MEM_COMMIT,
windows.PAGE_READWRITE) windows.PAGE_READWRITE)
if err != nil { if err != nil {
return fmt.Errorf("Error allocating memory block: %w", err) return fmt.Errorf("error allocating memory block: %w", err)
} }
} }
return return

View file

@ -40,7 +40,7 @@ var (
) )
func (wintun *Adapter) StartSession(capacity uint32) (session Session, err error) { func (wintun *Adapter) StartSession(capacity uint32) (session Session, err error) {
r0, _, e1 := syscall.Syscall(procWintunStartSession.Addr(), 2, uintptr(wintun.handle), uintptr(capacity), 0) r0, _, e1 := syscall.SyscallN(procWintunStartSession.Addr(), uintptr(wintun.handle), uintptr(capacity))
if r0 == 0 { if r0 == 0 {
err = e1 err = e1
} else { } else {
@ -50,19 +50,18 @@ func (wintun *Adapter) StartSession(capacity uint32) (session Session, err error
} }
func (session Session) End() { func (session Session) End() {
syscall.Syscall(procWintunEndSession.Addr(), 1, session.handle, 0, 0) syscall.SyscallN(procWintunEndSession.Addr(), session.handle)
session.handle = 0
} }
func (session Session) ReadWaitEvent() (handle windows.Handle) { func (session Session) ReadWaitEvent() (handle windows.Handle) {
r0, _, _ := syscall.Syscall(procWintunGetReadWaitEvent.Addr(), 1, session.handle, 0, 0) r0, _, _ := syscall.SyscallN(procWintunGetReadWaitEvent.Addr(), session.handle)
handle = windows.Handle(r0) handle = windows.Handle(r0)
return return
} }
func (session Session) ReceivePacket() (packet []byte, err error) { func (session Session) ReceivePacket() (packet []byte, err error) {
var packetSize uint32 var packetSize uint32
r0, _, e1 := syscall.Syscall(procWintunReceivePacket.Addr(), 2, session.handle, uintptr(unsafe.Pointer(&packetSize)), 0) r0, _, e1 := syscall.SyscallN(procWintunReceivePacket.Addr(), session.handle, uintptr(unsafe.Pointer(&packetSize)))
if r0 == 0 { if r0 == 0 {
err = e1 err = e1
return return
@ -72,11 +71,11 @@ func (session Session) ReceivePacket() (packet []byte, err error) {
} }
func (session Session) ReleaseReceivePacket(packet []byte) { func (session Session) ReleaseReceivePacket(packet []byte) {
syscall.Syscall(procWintunReleaseReceivePacket.Addr(), 2, session.handle, uintptr(unsafe.Pointer(&packet[0])), 0) syscall.SyscallN(procWintunReleaseReceivePacket.Addr(), session.handle, uintptr(unsafe.Pointer(&packet[0])))
} }
func (session Session) AllocateSendPacket(packetSize int) (packet []byte, err error) { func (session Session) AllocateSendPacket(packetSize int) (packet []byte, err error) {
r0, _, e1 := syscall.Syscall(procWintunAllocateSendPacket.Addr(), 2, session.handle, uintptr(packetSize), 0) r0, _, e1 := syscall.SyscallN(procWintunAllocateSendPacket.Addr(), session.handle, uintptr(packetSize))
if r0 == 0 { if r0 == 0 {
err = e1 err = e1
return return
@ -86,5 +85,5 @@ func (session Session) AllocateSendPacket(packetSize int) (packet []byte, err er
} }
func (session Session) SendPacket(packet []byte) { func (session Session) SendPacket(packet []byte) {
syscall.Syscall(procWintunSendPacket.Addr(), 2, session.handle, uintptr(unsafe.Pointer(&packet[0])), 0) syscall.SyscallN(procWintunSendPacket.Addr(), session.handle, uintptr(unsafe.Pointer(&packet[0])))
} }

View file

@ -30,7 +30,7 @@ var (
) )
func closeAdapter(wintun *Adapter) { func closeAdapter(wintun *Adapter) {
syscall.SyscallN(procWintunCloseAdapter.Addr(), 1, wintun.handle, 0, 0) syscall.SyscallN(procWintunCloseAdapter.Addr(), wintun.handle)
} }
// CreateAdapter creates a Wintun adapter. name is the cosmetic name of the adapter. // CreateAdapter creates a Wintun adapter. name is the cosmetic name of the adapter.
@ -53,7 +53,7 @@ func CreateAdapter(name string, tunnelType string, requestedGUID *windows.GUID)
if err != nil { if err != nil {
return return
} }
r0, _, e1 := syscall.Syscall(procWintunCreateAdapter.Addr(), 3, uintptr(unsafe.Pointer(name16)), uintptr(unsafe.Pointer(tunnelType16)), uintptr(unsafe.Pointer(requestedGUID))) r0, _, e1 := syscall.SyscallN(procWintunCreateAdapter.Addr(), uintptr(unsafe.Pointer(name16)), uintptr(unsafe.Pointer(tunnelType16)), uintptr(unsafe.Pointer(requestedGUID)))
if r0 == 0 { if r0 == 0 {
err = e1 err = e1
return return
@ -70,7 +70,7 @@ func OpenAdapter(name string) (wintun *Adapter, err error) {
if err != nil { if err != nil {
return return
} }
r0, _, e1 := syscall.Syscall(procWintunOpenAdapter.Addr(), 1, uintptr(unsafe.Pointer(name16)), 0, 0) r0, _, e1 := syscall.SyscallN(procWintunOpenAdapter.Addr(), uintptr(unsafe.Pointer(name16)))
if r0 == 0 { if r0 == 0 {
err = e1 err = e1
return return
@ -83,7 +83,7 @@ func OpenAdapter(name string) (wintun *Adapter, err error) {
// Close closes a Wintun adapter. // Close closes a Wintun adapter.
func (wintun *Adapter) Close() (err error) { func (wintun *Adapter) Close() (err error) {
runtime.SetFinalizer(wintun, nil) runtime.SetFinalizer(wintun, nil)
r1, _, e1 := syscall.Syscall(procWintunCloseAdapter.Addr(), 1, wintun.handle, 0, 0) r1, _, e1 := syscall.SyscallN(procWintunCloseAdapter.Addr(), wintun.handle)
if r1 == 0 { if r1 == 0 {
err = e1 err = e1
} }
@ -92,7 +92,7 @@ func (wintun *Adapter) Close() (err error) {
// Uninstall removes the driver from the system if no drivers are currently in use. // Uninstall removes the driver from the system if no drivers are currently in use.
func Uninstall() (err error) { func Uninstall() (err error) {
r1, _, e1 := syscall.Syscall(procWintunDeleteDriver.Addr(), 0, 0, 0, 0) r1, _, e1 := syscall.SyscallN(procWintunDeleteDriver.Addr())
if r1 == 0 { if r1 == 0 {
err = e1 err = e1
} }
@ -101,7 +101,7 @@ func Uninstall() (err error) {
// RunningVersion returns the version of the running Wintun driver. // RunningVersion returns the version of the running Wintun driver.
func RunningVersion() (version uint32, err error) { func RunningVersion() (version uint32, err error) {
r0, _, e1 := syscall.Syscall(procWintunGetRunningDriverVersion.Addr(), 0, 0, 0, 0) r0, _, e1 := syscall.SyscallN(procWintunGetRunningDriverVersion.Addr())
version = uint32(r0) version = uint32(r0)
if version == 0 { if version == 0 {
err = e1 err = e1
@ -111,6 +111,6 @@ func RunningVersion() (version uint32, err error) {
// LUID returns the LUID of the adapter. // LUID returns the LUID of the adapter.
func (wintun *Adapter) LUID() (luid uint64) { func (wintun *Adapter) LUID() (luid uint64) {
syscall.Syscall(procWintunGetAdapterLUID.Addr(), 2, uintptr(wintun.handle), uintptr(unsafe.Pointer(&luid)), 0) syscall.SyscallN(procWintunGetAdapterLUID.Addr(), uintptr(wintun.handle), uintptr(unsafe.Pointer(&luid)))
return return
} }

View file

@ -173,7 +173,8 @@ func (h *nfqueueHandler) handlePacket(attr nfqueue.Attribute) int {
var tcpOffset int var tcpOffset int
version := payload[0] >> 4 version := payload[0] >> 4
if version == 4 { switch version {
case 4:
ipv4 := header.IPv4(payload) ipv4 := header.IPv4(payload)
if !ipv4.IsValid(len(payload)) || ipv4.Protocol() != uint8(unix.IPPROTO_TCP) { if !ipv4.IsValid(len(payload)) || ipv4.Protocol() != uint8(unix.IPPROTO_TCP) {
h.setVerdict(packetID, nfqueue.NfAccept, 0) h.setVerdict(packetID, nfqueue.NfAccept, 0)
@ -182,7 +183,7 @@ func (h *nfqueueHandler) handlePacket(attr nfqueue.Attribute) int {
srcAddr = M.SocksaddrFrom(ipv4.SourceAddr(), 0) srcAddr = M.SocksaddrFrom(ipv4.SourceAddr(), 0)
dstAddr = M.SocksaddrFrom(ipv4.DestinationAddr(), 0) dstAddr = M.SocksaddrFrom(ipv4.DestinationAddr(), 0)
tcpOffset = int(ipv4.HeaderLength()) tcpOffset = int(ipv4.HeaderLength())
} else if version == 6 { case 6:
transportProto, transportOffset, ok := parseIPv6TransportHeader(payload) transportProto, transportOffset, ok := parseIPv6TransportHeader(payload)
if !ok || transportProto != unix.IPPROTO_TCP { if !ok || transportProto != unix.IPPROTO_TCP {
h.setVerdict(packetID, nfqueue.NfAccept, 0) h.setVerdict(packetID, nfqueue.NfAccept, 0)
@ -192,7 +193,7 @@ func (h *nfqueueHandler) handlePacket(attr nfqueue.Attribute) int {
srcAddr = M.SocksaddrFrom(ipv6.SourceAddr(), 0) srcAddr = M.SocksaddrFrom(ipv6.SourceAddr(), 0)
dstAddr = M.SocksaddrFrom(ipv6.DestinationAddr(), 0) dstAddr = M.SocksaddrFrom(ipv6.DestinationAddr(), 0)
tcpOffset = transportOffset tcpOffset = transportOffset
} else { default:
h.setVerdict(packetID, nfqueue.NfAccept, 0) h.setVerdict(packetID, nfqueue.NfAccept, 0)
return 0 return 0
} }

View file

@ -68,7 +68,7 @@ func NewStack(
func HasNextAddress(prefix netip.Prefix, count int) bool { func HasNextAddress(prefix netip.Prefix, count int) bool {
checkAddr := prefix.Addr() checkAddr := prefix.Addr()
for i := 0; i < count; i++ { for range count {
checkAddr = checkAddr.Next() checkAddr = checkAddr.Next()
} }
return prefix.Contains(checkAddr) return prefix.Contains(checkAddr)

View file

@ -131,7 +131,7 @@ func (s *System) start() error {
var tcpListener net.Listener var tcpListener net.Listener
var err error var err error
if s.inet4NextAddress.IsValid() { if s.inet4NextAddress.IsValid() {
for i := 0; i < 3; i++ { for range 3 {
tcpListener, err = listener.Listen(s.ctx, "tcp4", net.JoinHostPort(s.inet4Address.String(), "0")) tcpListener, err = listener.Listen(s.ctx, "tcp4", net.JoinHostPort(s.inet4Address.String(), "0"))
if !retryableListenError(err) { if !retryableListenError(err) {
break break
@ -146,7 +146,7 @@ func (s *System) start() error {
go s.acceptLoop(tcpListener) go s.acceptLoop(tcpListener)
} }
if s.inet6NextAddress.IsValid() { if s.inet6NextAddress.IsValid() {
for i := 0; i < 3; i++ { for range 3 {
tcpListener, err = listener.Listen(s.ctx, "tcp6", net.JoinHostPort(s.inet6Address.String(), "0")) tcpListener, err = listener.Listen(s.ctx, "tcp6", net.JoinHostPort(s.inet6Address.String(), "0"))
if !retryableListenError(err) { if !retryableListenError(err) {
break break
@ -245,7 +245,7 @@ func (s *System) batchLoopLinux(linuxTUN LinuxTUN, batchSize int) {
if n == 0 { if n == 0 {
continue continue
} }
for i := 0; i < n; i++ { for i := range n {
packetSize := packetSizes[i] packetSize := packetSizes[i]
if packetSize < header.IPv4MinimumSize { if packetSize < header.IPv4MinimumSize {
continue continue

View file

@ -132,7 +132,7 @@ func New(options Options) (Tun, error) {
stopFd: common.Must1(stopfd.New()), stopFd: common.Must1(stopfd.New()),
sendMsgX: options.EXP_SendMsgX, sendMsgX: options.EXP_SendMsgX,
} }
for i := 0; i < batchSize; i++ { for i := range batchSize {
nativeTun.iovecs[i] = newIovecBuffer(int(options.MTU)) nativeTun.iovecs[i] = newIovecBuffer(int(options.MTU))
nativeTun.iovecsOutput[i] = newIovecBuffer(int(options.MTU)) nativeTun.iovecsOutput[i] = newIovecBuffer(int(options.MTU))
} }
@ -352,7 +352,7 @@ func (t *NativeTun) BatchRead() ([]*buf.Buffer, error) {
} }
n, errno := rawfile.BlockingRecvMMsgUntilStopped(t.stopFd.ReadFD, t.tunFd, t.msgHdrs) n, errno := rawfile.BlockingRecvMMsgUntilStopped(t.stopFd.ReadFD, t.tunFd, t.msgHdrs)
if errno != 0 { if errno != 0 {
for k := 0; k < n; k++ { for k := range n {
t.iovecs[k].buffer.Release() t.iovecs[k].buffer.Release()
t.iovecs[k].buffer = nil t.iovecs[k].buffer = nil
} }
@ -366,7 +366,7 @@ func (t *NativeTun) BatchRead() ([]*buf.Buffer, error) {
return nil, nil return nil, nil
} }
buffers := t.buffers buffers := t.buffers
for k := 0; k < n; k++ { for k := range n {
buffer := t.iovecs[k].buffer buffer := t.iovecs[k].buffer
t.iovecs[k].buffer = nil t.iovecs[k].buffer = nil
buffer.Truncate(int(t.msgHdrs[k].DataLen) - PacketOffset) buffer.Truncate(int(t.msgHdrs[k].DataLen) - PacketOffset)

View file

@ -42,7 +42,6 @@ type NativeTun struct {
vnetHdrWriteBuf []byte vnetHdrWriteBuf []byte
gsoToWrite []int gsoToWrite []int
tcpGROTable *tcpGROTable tcpGROTable *tcpGROTable
udpGroAccess sync.Mutex
udpGROTable *udpGROTable udpGROTable *udpGROTable
gro groDisablementFlags gro groDisablementFlags
txChecksumOffload bool txChecksumOffload bool

View file

@ -9,11 +9,6 @@ import (
"github.com/sagernet/sing-tun/internal/gtcpip/header" "github.com/sagernet/sing-tun/internal/gtcpip/header"
) )
const (
gsoMaxSize = 65536
idealBatchSize = 128
)
// GSOType represents the type of segmentation offload. // GSOType represents the type of segmentation offload.
type GSOType int type GSOType int
@ -167,10 +162,7 @@ func GSOSplit(in []byte, options GSOOptions, outBufs [][]byte, sizes []int, outO
if i == len(outBufs) { if i == len(outBufs) {
return i - 1, ErrTooManySegments return i - 1, ErrTooManySegments
} }
nextSegmentEnd := nextSegmentDataAt + int(options.GSOSize) nextSegmentEnd := min(nextSegmentDataAt+int(options.GSOSize), len(in))
if nextSegmentEnd > len(in) {
nextSegmentEnd = len(in)
}
segmentDataLen := nextSegmentEnd - nextSegmentDataAt segmentDataLen := nextSegmentEnd - nextSegmentDataAt
totalLen := int(options.HdrLen) + segmentDataLen totalLen := int(options.HdrLen) + segmentDataLen
sizes[i] = totalLen sizes[i] = totalLen

View file

@ -11,6 +11,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"slices"
"unsafe" "unsafe"
"github.com/sagernet/sing-tun/internal/gtcpip" "github.com/sagernet/sing-tun/internal/gtcpip"
@ -20,6 +21,11 @@ import (
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
const (
gsoMaxSize = 65536
idealBatchSize = 128
)
// virtioNetHdr is defined in the kernel in include/uapi/linux/virtio_net.h. The // virtioNetHdr is defined in the kernel in include/uapi/linux/virtio_net.h. The
// kernel symbol is virtio_net_hdr. // kernel symbol is virtio_net_hdr.
type virtioNetHdr struct { type virtioNetHdr struct {
@ -606,7 +612,7 @@ func tcpGRO(bufs [][]byte, offset int, pktI int, table *tcpGROTable, isV6 bool)
if !existing { if !existing {
return groResultTableInsert return groResultTableInsert
} }
for i := len(items) - 1; i >= 0; i-- { for i, item := range slices.Backward(items) {
// In the best case of packets arriving in order iterating in reverse is // In the best case of packets arriving in order iterating in reverse is
// more efficient if there are multiple items for a given flow. This // more efficient if there are multiple items for a given flow. This
// also enables a natural table.deleteAt() in the // also enables a natural table.deleteAt() in the
@ -615,7 +621,6 @@ func tcpGRO(bufs [][]byte, offset int, pktI int, table *tcpGROTable, isV6 bool)
// unordered packets, where pkt may land anywhere in items from a // unordered packets, where pkt may land anywhere in items from a
// sequence number perspective, however once an item is inserted into // sequence number perspective, however once an item is inserted into
// the table it is never compared across other items later. // the table it is never compared across other items later.
item := items[i]
can := tcpPacketsCanCoalesce(pkt, uint8(iphLen), uint8(tcphLen), seq, pshSet, gsoSize, item, bufs, offset) can := tcpPacketsCanCoalesce(pkt, uint8(iphLen), uint8(tcphLen), seq, pshSet, gsoSize, item, bufs, offset)
if can != coalesceUnavailable { if can != coalesceUnavailable {
result := coalesceTCPPackets(can, pkt, pktI, gsoSize, seq, pshSet, &item, bufs, offset, isV6) result := coalesceTCPPackets(can, pkt, pktI, gsoSize, seq, pshSet, &item, bufs, offset, isV6)
@ -793,7 +798,8 @@ func packetIsGROCandidate(b []byte, gro groDisablementFlags) groCandidateType {
if len(b) < 28 { if len(b) < 28 {
return notGROCandidate return notGROCandidate
} }
if b[0]>>4 == 4 { switch b[0] >> 4 {
case 4:
if b[0]&0x0F != 5 { if b[0]&0x0F != 5 {
// IPv4 packets w/IP options do not coalesce // IPv4 packets w/IP options do not coalesce
return notGROCandidate return notGROCandidate
@ -804,7 +810,7 @@ func packetIsGROCandidate(b []byte, gro groDisablementFlags) groCandidateType {
if b[9] == unix.IPPROTO_UDP && gro.canUDPGRO() { if b[9] == unix.IPPROTO_UDP && gro.canUDPGRO() {
return udp4GROCandidate return udp4GROCandidate
} }
} else if b[0]>>4 == 6 { case 6:
if b[6] == unix.IPPROTO_TCP && len(b) >= 60 && gro.canTCPGRO() { if b[6] == unix.IPPROTO_TCP && len(b) >= 60 && gro.canTCPGRO() {
return tcp6GROCandidate return tcp6GROCandidate
} }