Skip to content

Commit 7ce8acd

Browse files
committed
tunnel+conf+ui: periodic update of endpoint ip
1 parent 32b3cb6 commit 7ce8acd

File tree

8 files changed

+129
-18
lines changed

8 files changed

+129
-18
lines changed

conf/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,12 @@ type Peer struct {
5757
AllowedIPs []netip.Prefix
5858
Endpoint Endpoint
5959
PersistentKeepalive uint16
60+
UpdateEndpointIP uint16
6061

6162
RxBytes Bytes
6263
TxBytes Bytes
6364
LastHandshakeTime HandshakeTime
65+
UnresolvedHost string
6466
}
6567

6668
func (conf *Config) IntersectsWith(other *Config) bool {

conf/dnsresolver_windows.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import (
1919

2020
//sys internetGetConnectedState(flags *uint32, reserved uint32) (connected bool) = wininet.InternetGetConnectedState
2121

22-
func resolveHostname(name string) (resolvedIPString string, err error) {
22+
func ResolveHostname(name string) (resolvedIPString string, err error) {
2323
maxTries := 10
2424
if services.StartedAtBoot() {
2525
maxTries *= 4
@@ -90,8 +90,11 @@ func (config *Config) ResolveEndpoints() error {
9090
if config.Peers[i].Endpoint.IsEmpty() {
9191
continue
9292
}
93+
if config.Peers[i].UpdateEndpointIP > 0 {
94+
config.Peers[i].UnresolvedHost = config.Peers[i].Endpoint.Host
95+
}
9396
var err error
94-
config.Peers[i].Endpoint.Host, err = resolveHostname(config.Peers[i].Endpoint.Host)
97+
config.Peers[i].Endpoint.Host, err = ResolveHostname(config.Peers[i].Endpoint.Host)
9598
if err != nil {
9699
return err
97100
}

conf/parser.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,20 @@ func parsePersistentKeepalive(s string) (uint16, error) {
109109
return uint16(m), nil
110110
}
111111

112+
func parseUpdateEndpointIP(s string) (uint16, error) {
113+
if s == "off" {
114+
return 0, nil
115+
}
116+
m, err := strconv.Atoi(s)
117+
if err != nil {
118+
return 0, err
119+
}
120+
if m < 0 || m > 65535 {
121+
return 0, &ParseError{l18n.Sprintf("Invalid update endpoint IP"), s}
122+
}
123+
return uint16(m), nil
124+
}
125+
112126
func parseTableOff(s string) (bool, error) {
113127
if s == "off" {
114128
return true, nil
@@ -294,6 +308,12 @@ func FromWgQuick(s string, name string) (*Config, error) {
294308
return nil, err
295309
}
296310
peer.PersistentKeepalive = p
311+
case "updateendpointip":
312+
p, err := parseUpdateEndpointIP(val)
313+
if err != nil {
314+
return nil, err
315+
}
316+
peer.UpdateEndpointIP = p
297317
case "endpoint":
298318
e, err := parseEndpoint(val)
299319
if err != nil {
@@ -378,6 +398,12 @@ func FromDriverConfiguration(interfaze *driver.Interface, existingConfig *Config
378398
if p.Flags&driver.PeerHasPersistentKeepalive != 0 {
379399
peer.PersistentKeepalive = p.PersistentKeepalive
380400
}
401+
for i := range existingConfig.Peers {
402+
if existingConfig.Peers[i].PublicKey == peer.PublicKey && existingConfig.Peers[i].UpdateEndpointIP > 0 {
403+
// Get UpdateEndpointIP option from config as it is cannot be retrieved from the driver
404+
peer.UpdateEndpointIP = existingConfig.Peers[i].UpdateEndpointIP
405+
}
406+
}
381407
peer.TxBytes = Bytes(p.TxBytes)
382408
peer.RxBytes = Bytes(p.RxBytes)
383409
if p.LastHandshake != 0 {

conf/writer.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ func (conf *Config) ToWgQuick() string {
8888
if peer.PersistentKeepalive > 0 {
8989
output.WriteString(fmt.Sprintf("PersistentKeepalive = %d\n", peer.PersistentKeepalive))
9090
}
91+
92+
if peer.UpdateEndpointIP > 0 {
93+
output.WriteString(fmt.Sprintf("UpdateEndpointIP = %d\n", peer.UpdateEndpointIP))
94+
}
9195
}
9296
return output.String()
9397
}
@@ -139,3 +143,24 @@ func (config *Config) ToDriverConfiguration() (*driver.Interface, uint32) {
139143
}
140144
return c.Interface()
141145
}
146+
147+
func PeerUpdateEndpointConfiguration(peer *Peer, newIP string) (*driver.Interface, uint32) {
148+
preallocation := unsafe.Sizeof(driver.Interface{}) + uintptr(1)*unsafe.Sizeof(driver.Peer{})
149+
var c driver.ConfigBuilder
150+
c.Preallocate(uint32(preallocation))
151+
c.AppendInterface(&driver.Interface{
152+
PeerCount: uint32(1),
153+
})
154+
155+
var endpoint winipcfg.RawSockaddrInet
156+
addr, err := netip.ParseAddr(newIP)
157+
if err == nil {
158+
endpoint.SetAddrPort(netip.AddrPortFrom(addr, peer.Endpoint.Port))
159+
}
160+
c.AppendPeer(&driver.Peer{
161+
Flags: driver.PeerHasEndpoint | driver.PeerHasPublicKey,
162+
PublicKey: peer.PublicKey,
163+
Endpoint: endpoint,
164+
})
165+
return c.Interface()
166+
}

tunnel/service.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@ func (service *tunnelService) Execute(args []string, r <-chan svc.ChangeRequest,
219219
return
220220
}
221221

222+
startUpdateEndpointIP(adapter, config)
223+
222224
changes <- svc.Status{State: serviceState, Accepts: svc.AcceptStop | svc.AcceptShutdown}
223225

224226
var started bool
@@ -247,6 +249,37 @@ func (service *tunnelService) Execute(args []string, r <-chan svc.ChangeRequest,
247249
}
248250
}
249251

252+
func startUpdateEndpointIP(adapter *driver.Adapter, config *conf.Config) {
253+
for i := range config.Peers {
254+
if !config.Peers[i].Endpoint.IsEmpty() && config.Peers[i].UpdateEndpointIP > 0 {
255+
go resolveDNSLoop(adapter, &config.Peers[i], i+1)
256+
}
257+
}
258+
}
259+
260+
func resolveDNSLoop(adapter *driver.Adapter, peer *conf.Peer, peerNumber int) {
261+
for {
262+
time.Sleep(time.Second * time.Duration(peer.UpdateEndpointIP))
263+
264+
log.Printf("Checking DNS of endpoint for peer %d", peerNumber)
265+
resolvedIPString, err := conf.ResolveHostname(peer.UnresolvedHost)
266+
if err != nil {
267+
log.Printf("Error resolving hostname of peer %d", peerNumber)
268+
continue
269+
}
270+
271+
if resolvedIPString != peer.Endpoint.Host {
272+
peer.Endpoint.Host = resolvedIPString
273+
err = adapter.SetConfiguration(conf.PeerUpdateEndpointConfiguration(peer, resolvedIPString))
274+
if err == nil {
275+
log.Printf("IP for peer %d updated (%v)", peerNumber, resolvedIPString)
276+
} else {
277+
log.Printf("Error updating IP for peer %d: %v", peerNumber, err)
278+
}
279+
}
280+
}
281+
}
282+
250283
func Run(confPath string) error {
251284
name, err := conf.NameFromPath(confPath)
252285
if err != nil {

ui/confview.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ type peerView struct {
6262
allowedIPs *labelTextLine
6363
endpoint *labelTextLine
6464
persistentKeepalive *labelTextLine
65+
updateEndpointIP *labelTextLine
6566
latestHandshake *labelTextLine
6667
transfer *labelTextLine
6768
lines []widgetsLine
@@ -337,6 +338,7 @@ func newPeerView(parent walk.Container) (*peerView, error) {
337338
{l18n.Sprintf("Allowed IPs:"), &pv.allowedIPs},
338339
{l18n.Sprintf("Endpoint:"), &pv.endpoint},
339340
{l18n.Sprintf("Persistent keepalive:"), &pv.persistentKeepalive},
341+
{l18n.Sprintf("Update endpoint IP:"), &pv.updateEndpointIP},
340342
{l18n.Sprintf("Latest handshake:"), &pv.latestHandshake},
341343
{l18n.Sprintf("Transfer:"), &pv.transfer},
342344
}
@@ -476,6 +478,12 @@ func (pv *peerView) apply(c *conf.Peer) {
476478
pv.persistentKeepalive.hide()
477479
}
478480

481+
if c.UpdateEndpointIP > 0 {
482+
pv.updateEndpointIP.show(strconv.Itoa(int(c.UpdateEndpointIP)))
483+
} else {
484+
pv.updateEndpointIP.hide()
485+
}
486+
479487
if !c.LastHandshakeTime.IsEmpty() {
480488
pv.latestHandshake.show(c.LastHandshakeTime.String())
481489
} else {

ui/syntax/highlighter.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const (
2424
highlightPort
2525
highlightMTU
2626
highlightKeepalive
27+
highlightUpdateEndpointIP
2728
highlightComment
2829
highlightDelimiter
2930
highlightTable
@@ -268,6 +269,13 @@ func (s stringSpan) isValidPersistentKeepAlive() bool {
268269
return s.isValidUint(false, 0, 65535)
269270
}
270271

272+
func (s stringSpan) isValidUpdateEndpointIP() bool {
273+
if s.isSame("off") {
274+
return true
275+
}
276+
return s.isValidUint(false, 0, 65535)
277+
}
278+
271279
// It's probably not worthwhile to try to validate a bash expression. So instead we just demand non-zero length.
272280
func (s stringSpan) isValidPrePostUpDown() bool {
273281
return s.len != 0
@@ -376,6 +384,7 @@ const (
376384
fieldAllowedIPs
377385
fieldEndpoint
378386
fieldPersistentKeepalive
387+
fieldUpdateEndpointIP
379388
fieldInvalid
380389
)
381390

@@ -413,6 +422,8 @@ func (s stringSpan) field() field {
413422
return fieldEndpoint
414423
case s.isCaselessSame("PersistentKeepalive"):
415424
return fieldPersistentKeepalive
425+
case s.isCaselessSame("UpdateEndpointIP"):
426+
return fieldUpdateEndpointIP
416427
case s.isCaselessSame("PreUp"):
417428
return fieldPreUp
418429
case s.isCaselessSame("PostUp"):
@@ -524,6 +535,8 @@ func (hsa *highlightSpanArray) highlightValue(parent stringSpan, s stringSpan, s
524535
hsa.append(parent.s, s, validateHighlight(s.isValidPort(), highlightPort))
525536
case fieldPersistentKeepalive:
526537
hsa.append(parent.s, s, validateHighlight(s.isValidPersistentKeepAlive(), highlightKeepalive))
538+
case fieldUpdateEndpointIP:
539+
hsa.append(parent.s, s, validateHighlight(s.isValidUpdateEndpointIP(), highlightUpdateEndpointIP))
527540
case fieldEndpoint:
528541
if !s.isValidEndpoint() {
529542
hsa.append(parent.s, s, highlightError)

ui/syntax/syntaxedit.go

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -90,22 +90,23 @@ type spanStyle struct {
9090
}
9191

9292
var stylemap = map[highlight]spanStyle{
93-
highlightSection: spanStyle{color: win.RGB(0x32, 0x6D, 0x74), effects: win.CFE_BOLD},
94-
highlightField: spanStyle{color: win.RGB(0x9B, 0x23, 0x93), effects: win.CFE_BOLD},
95-
highlightPrivateKey: spanStyle{color: win.RGB(0x64, 0x38, 0x20)},
96-
highlightPublicKey: spanStyle{color: win.RGB(0x64, 0x38, 0x20)},
97-
highlightPresharedKey: spanStyle{color: win.RGB(0x64, 0x38, 0x20)},
98-
highlightIP: spanStyle{color: win.RGB(0x0E, 0x0E, 0xFF)},
99-
highlightCidr: spanStyle{color: win.RGB(0x81, 0x5F, 0x03)},
100-
highlightHost: spanStyle{color: win.RGB(0x0E, 0x0E, 0xFF)},
101-
highlightPort: spanStyle{color: win.RGB(0x81, 0x5F, 0x03)},
102-
highlightMTU: spanStyle{color: win.RGB(0x1C, 0x00, 0xCF)},
103-
highlightTable: spanStyle{color: win.RGB(0x1C, 0x00, 0xCF)},
104-
highlightKeepalive: spanStyle{color: win.RGB(0x1C, 0x00, 0xCF)},
105-
highlightComment: spanStyle{color: win.RGB(0x53, 0x65, 0x79), effects: win.CFE_ITALIC},
106-
highlightDelimiter: spanStyle{color: win.RGB(0x00, 0x00, 0x00)},
107-
highlightCmd: spanStyle{color: win.RGB(0x63, 0x75, 0x89)},
108-
highlightError: spanStyle{color: win.RGB(0xC4, 0x1A, 0x16), effects: win.CFE_UNDERLINE},
93+
highlightSection: spanStyle{color: win.RGB(0x32, 0x6D, 0x74), effects: win.CFE_BOLD},
94+
highlightField: spanStyle{color: win.RGB(0x9B, 0x23, 0x93), effects: win.CFE_BOLD},
95+
highlightPrivateKey: spanStyle{color: win.RGB(0x64, 0x38, 0x20)},
96+
highlightPublicKey: spanStyle{color: win.RGB(0x64, 0x38, 0x20)},
97+
highlightPresharedKey: spanStyle{color: win.RGB(0x64, 0x38, 0x20)},
98+
highlightIP: spanStyle{color: win.RGB(0x0E, 0x0E, 0xFF)},
99+
highlightCidr: spanStyle{color: win.RGB(0x81, 0x5F, 0x03)},
100+
highlightHost: spanStyle{color: win.RGB(0x0E, 0x0E, 0xFF)},
101+
highlightPort: spanStyle{color: win.RGB(0x81, 0x5F, 0x03)},
102+
highlightMTU: spanStyle{color: win.RGB(0x1C, 0x00, 0xCF)},
103+
highlightTable: spanStyle{color: win.RGB(0x1C, 0x00, 0xCF)},
104+
highlightKeepalive: spanStyle{color: win.RGB(0x1C, 0x00, 0xCF)},
105+
highlightUpdateEndpointIP: spanStyle{color: win.RGB(0x1C, 0x00, 0xCF)},
106+
highlightComment: spanStyle{color: win.RGB(0x53, 0x65, 0x79), effects: win.CFE_ITALIC},
107+
highlightDelimiter: spanStyle{color: win.RGB(0x00, 0x00, 0x00)},
108+
highlightCmd: spanStyle{color: win.RGB(0x63, 0x75, 0x89)},
109+
highlightError: spanStyle{color: win.RGB(0xC4, 0x1A, 0x16), effects: win.CFE_UNDERLINE},
109110
}
110111

111112
func (se *SyntaxEdit) evaluateUntunneledBlocking(cfg string, spans []highlightSpan) {

0 commit comments

Comments
 (0)