Kerio on Linux: giving kvnet the MAC the server expects
kvnet is recreated on every connect, so a one-time address change is lost. Read the value the client logged and apply it from a post-connect hook.
Three things have to agree before a Kerio tunnel carries traffic: the address on the kvnet interface, the value the client logged, and what the server policy or DHCP expects. When they disagree the tunnel still authenticates and still comes up, which is exactly what makes the failure confusing. The interface is created per connection, so an address set by hand belongs to that session and nothing else. That is the shape of the problem, and the fix is a hook rather than a configuration file. The rest is where to read the value and where to apply it.
Why the address keeps reverting
kvnet is a virtual adapter the client creates when a connection starts and removes when it ends. A manual ip link set therefore survives exactly as long as the session it was applied to, and the next connection starts from whatever the client assigns. On a machine where the client fails to apply the expected address, every reconnect reintroduces the same mismatch, and the lease or access rule rejects the device again.
That pattern is diagnostic on its own. A tunnel that works for one session and fails on the next is not a credential problem, because credentials do not change between connects.
Read the value from the client, not the interface
The Linux client writes negotiation detail to its debug log, and the address it means to use appears there as the last address-shaped token of the connection sequence. Compare that with what the kernel actually holds, which is one readlink away: cat /sys/class/net/kvnet/address.
If the two differ, the client knew the right value and failed to apply it, and a hook that applies it after the interface exists closes the gap. If the log contains no address at all, the problem is earlier and belongs with the client version or the server profile rather than with a script.
Apply it after the interface exists
NetworkManager users can drop a script into its dispatcher directory and act only when the VPN interface comes up. A systemd-managed client needs more care: a drop-in that runs at service start usually fires before the adapter exists, so the hook has to wait for the interface instead of assuming it. Set the address then, and if the kernel refuses while the link is up, take it down, set it, and bring it back up. Read the extracted token back through a MAC pattern before passing it to ip link, so an unexpected log line cannot become an argument.
Anything that runs as root from a client's log deserves narrow ownership: a root-owned file, not writable by others, and no shell interpolation beyond the validated address. Keep the pattern check inside the script. Do not let log content decide which command runs.
Verify the lease rather than the link
ip -4 -o addr show dev kvnet should show an address in the expected range, ip neigh show dev kvnet should show the gateway, and one service behind the VPN should answer. Then disconnect and reconnect once; if the address reverts, the hook is firing on the wrong event or not firing at all.
An interface that appears with the right address and never gets a lease points at the server side. That is a different check and usually a different team. Confirm that the account is permitted and the pool still has an address before editing the hook again.
Revisit the workaround after an upgrade
A client build that sets the address correctly leaves your hook applying a stale value, which is a new fault introduced by a fix. Never copy a MAC from another machine or a forum post either; use the value this client logs for this account, and record the date you verified it.
Keep the script short enough to read in one sitting. Workarounds that parse logs are temporary by nature. The ones that survive are the ones a future reader can understand without the original thread.