Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
favonia committed Sep 22, 2024
1 parent 2d95d69 commit aeb036d
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 11 deletions.
2 changes: 1 addition & 1 deletion internal/provider/local_cloudflare.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
// NewLocal creates a specialized Local provider that uses Cloudflare as the remote server.
// (No actual UDP packets will be sent to Cloudflare.)
func NewLocal() Provider {
return protocol.Local{
return protocol.LocalAuto{
ProviderName: "local",
RemoteUDPAddr: map[ipnet.Type]string{
// 1.0.0.1 is used in case 1.1.1.1 is hijacked by the router
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import (
"github.com/favonia/cloudflare-ddns/internal/pp"
)

// Local detects the IP address by pretending to send out an UDP packet
// LocalAuto detects the IP address by pretending to send out an UDP packet
// and using the source IP address assigned by the system. In most cases
// it will detect the IP address of the network interface toward the internet.
// (No actual UDP packets will be sent out.)
type Local struct {
type LocalAuto struct {
// Name of the detection protocol.
ProviderName string

Expand All @@ -22,25 +22,23 @@ type Local struct {
}

// Name of the detection protocol.
func (p Local) Name() string {
func (p LocalAuto) Name() string {
return p.ProviderName
}

// GetIP detects the IP address by pretending to send an UDP packet.
// (No actual UDP packets will be sent out.)
func (p Local) GetIP(_ context.Context, ppfmt pp.PP, ipNet ipnet.Type) (netip.Addr, Method, bool) {
var invalidIP netip.Addr

func (p LocalAuto) GetIP(_ context.Context, ppfmt pp.PP, ipNet ipnet.Type) (netip.Addr, Method, bool) {
remoteUDPAddr, found := p.RemoteUDPAddr[ipNet]
if !found {
ppfmt.Noticef(pp.EmojiImpossible, "Unhandled IP network: %s", ipNet.Describe())
return invalidIP, MethodUnspecified, false
return netip.Addr{}, MethodUnspecified, false
}

conn, err := net.Dial(ipNet.UDPNetwork(), remoteUDPAddr)
if err != nil {
ppfmt.Noticef(pp.EmojiError, "Failed to detect a local %s address: %v", ipNet.Describe(), err)
return invalidIP, MethodUnspecified, false
return netip.Addr{}, MethodUnspecified, false
}
defer conn.Close()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
func TestLocalName(t *testing.T) {
t.Parallel()

p := &protocol.Local{
p := &protocol.LocalAuto{
ProviderName: "very secret name",
RemoteUDPAddr: nil,
}
Expand Down Expand Up @@ -102,7 +102,7 @@ func TestLocalGetIP(t *testing.T) {
t.Parallel()
mockCtrl := gomock.NewController(t)

provider := &protocol.Local{
provider := &protocol.LocalAuto{
ProviderName: "",
RemoteUDPAddr: map[ipnet.Type]string{
tc.addrKey: tc.addr,
Expand Down
55 changes: 55 additions & 0 deletions internal/provider/protocol/local_iface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package protocol

import (
"context"
"net"
"net/netip"

"github.com/favonia/cloudflare-ddns/internal/ipnet"
"github.com/favonia/cloudflare-ddns/internal/pp"
)

// LocalWithInterface detects the IP address by choosing the first "good" IP
// address assigned to a network interface.
type LocalWithInterface struct {
// Name of the detection protocol.
ProviderName string

// The name of the network interface
InterfaceName string
}

// Name of the detection protocol.
func (p LocalWithInterface) Name() string {
return p.ProviderName

Check warning on line 24 in internal/provider/protocol/local_iface.go

View check run for this annotation

Codecov / codecov/patch

internal/provider/protocol/local_iface.go#L23-L24

Added lines #L23 - L24 were not covered by tests
}

// GetIP detects the IP address by pretending to send an UDP packet.
// (No actual UDP packets will be sent out.)
func (p LocalWithInterface) GetIP(_ context.Context, ppfmt pp.PP, ipNet ipnet.Type) (netip.Addr, Method, bool) {
iface, err := net.InterfaceByName(p.InterfaceName)
if err != nil {
ppfmt.Noticef(pp.EmojiUserError, "Failed to find an interface named %q: %v", p.InterfaceName, err)
return netip.Addr{}, MethodUnspecified, false

Check warning on line 33 in internal/provider/protocol/local_iface.go

View check run for this annotation

Codecov / codecov/patch

internal/provider/protocol/local_iface.go#L29-L33

Added lines #L29 - L33 were not covered by tests
}

addrs, err := iface.Addrs()
if err != nil {
ppfmt.Noticef(pp.EmojiUserError, "Failed to list addresses of %q: %v", p.InterfaceName, err)
return netip.Addr{}, MethodUnspecified, false

Check warning on line 39 in internal/provider/protocol/local_iface.go

View check run for this annotation

Codecov / codecov/patch

internal/provider/protocol/local_iface.go#L36-L39

Added lines #L36 - L39 were not covered by tests
}

for _, addr := range addrs {
ip, err := netip.ParseAddr(addr.String())
if err != nil {
ppfmt.Noticef(pp.EmojiUserError, "Failed to parse address %q of %q: %v", addr.String(), p.InterfaceName, err)
return netip.Addr{}, MethodUnspecified, false

Check warning on line 46 in internal/provider/protocol/local_iface.go

View check run for this annotation

Codecov / codecov/patch

internal/provider/protocol/local_iface.go#L42-L46

Added lines #L42 - L46 were not covered by tests
}

if ipNet.Matches(ip) && ip.IsGlobalUnicast() {
return ip, MethodUnspecified, true

Check warning on line 50 in internal/provider/protocol/local_iface.go

View check run for this annotation

Codecov / codecov/patch

internal/provider/protocol/local_iface.go#L49-L50

Added lines #L49 - L50 were not covered by tests
}
}

return netip.Addr{}, MethodUnspecified, false

Check warning on line 54 in internal/provider/protocol/local_iface.go

View check run for this annotation

Codecov / codecov/patch

internal/provider/protocol/local_iface.go#L54

Added line #L54 was not covered by tests
}

0 comments on commit aeb036d

Please sign in to comment.