ref: a4fa14a9d8f604d3e1eb409091b4f0d879f9cf97
parent: b76d35401c0a056911aa192d4e4e6d86a15efa50
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Apr 15 14:00:34 EDT 2023
ip: generalize Rproxy route handling, allowing non point-to-point arp proxy Generalize the arp proxy code, so one can create specific routes for ip ranges that we want to arp proxy for, not just for point-to-point interface routes. as we have source specific routes, this also gives some control over which requester we will reply to. one example for this is a vps where we booked another ip address on the ethernet, that we want to route into a vpn tunnel. the new ip is in subnet of the public ethernet interface, so all we now need todo is add a route for that ip into the vpn tunnel and set the proxy flag "y", and we will respond to arp for that ip on the public ethernet interface.
--- a/sys/src/9/ip/arp.c
+++ b/sys/src/9/ip/arp.c
@@ -383,7 +383,43 @@
return 1;
}
+/*
+ * arpforme() checks if we should respond to arp/ndp on a specific interface.
+ *
+ * returns Runi if targ is a non-tentative local address on ifc.
+ * returns Rproxy if we have a proxy route for targ to another interface.
+ */
int
+arpforme(Fs *fs, int version, uchar *targ, uchar *src, Ipifc *ifc)
+{
+ uchar ipv6[IPaddrlen];
+ Iplifc *lifc;
+ Route *r;
+
+ if(version == V4) {
+ v4tov6(ipv6, targ);
+ targ = ipv6;
+ }
+ lifc = iplocalonifc(ifc, targ);
+ if(lifc != nil){
+ if(lifc->tentative)
+ return 0;
+ return Runi;
+ }
+ if(ipremoteonifc(ifc, targ) == nil)
+ return 0;
+ if(version == V4){
+ targ += IPv4off;
+ r = v4lookup(fs, targ, src, nil);
+ } else {
+ r = v6lookup(fs, targ, src, nil);
+ }
+ if(r == nil || r->ifc == ifc && r->ifcid == ifc->ifcid)
+ return 0;
+ return r->type & Rproxy;
+}
+
+int
arpwrite(Fs *fs, char *s, int len)
{
int n;
@@ -552,8 +588,7 @@
if(a->last != nil){
ipmove(src, ((Ip6hdr*)a->last->rp)->src);
arpcontinue(f->arp, a);
-
- if(iplocalonifc(ifc, src) != nil || ipproxyifc(f, ifc, src))
+ if(arpforme(f, V6, src, targ, ifc))
goto send;
} else {
arpcontinue(f->arp, a);
--- a/sys/src/9/ip/ethermedium.c
+++ b/sys/src/9/ip/ethermedium.c
@@ -508,7 +508,6 @@
int forme;
Block *ebp, *rbp;
Etherarp *e, *r;
- uchar ip[IPaddrlen];
static uchar eprinted[4];
Etherrock *er = ifc->arg;
@@ -529,8 +528,7 @@
break;
/* check for machine using my ip address */
- v4tov6(ip, e->spa);
- if(iplocalonifc(ifc, ip) != nil || ipproxyifc(er->f, ifc, ip)){
+ if(arpforme(er->f, V4, e->spa, e->tpa, ifc)){
if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
print("arprep: 0x%E/0x%E also has ip addr %V\n",
e->s, e->sha, e->spa);
@@ -552,8 +550,7 @@
break;
/* check for machine using my ip or ether address */
- v4tov6(ip, e->spa);
- if(iplocalonifc(ifc, ip) != nil || ipproxyifc(er->f, ifc, ip)){
+ if(arpforme(er->f, V4, e->spa, e->tpa, ifc)){
if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
if(memcmp(eprinted, e->spa, sizeof(e->spa)) != 0){
/* print only once */
@@ -576,8 +573,7 @@
* enter senders address into arp table and reply, otherwise just
* refresh the senders address.
*/
- v4tov6(ip, e->tpa);
- forme = iplocalonifc(ifc, ip) != nil || ipproxyifc(er->f, ifc, ip);
+ forme = arpforme(er->f, V4, e->tpa, e->spa, ifc);
if(arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), e->tpa, ifc, !forme) < 0 || !forme)
break;
--- a/sys/src/9/ip/icmp6.c
+++ b/sys/src/9/ip/icmp6.c
@@ -636,21 +636,6 @@
return 0;
}
-static int
-targettype(Fs *f, Ipifc *ifc, uchar *target)
-{
- Iplifc *lifc;
- int t;
-
- if((lifc = iplocalonifc(ifc, target)) != nil)
- t = lifc->tentative? Tunitent: Tunirany;
- else if(ipproxyifc(f, ifc, target))
- t = Tuniproxy;
- else
- t = 0;
- return t;
-}
-
static void
icmpiput6(Proto *icmp, Ipifc *ifc, Block *bp)
{
@@ -745,12 +730,11 @@
pktflags = 0;
if(ifc->sendra6)
pktflags |= Rflag;
- switch (targettype(icmp->f, ifc, np->target)) {
- case Tunirany:
+ switch(arpforme(icmp->f, V6, np->target, np->src, ifc)){
+ case Runi:
pktflags |= Oflag;
- /* fall through */
-
- case Tuniproxy:
+ /* wet floor */
+ case Rproxy:
if(ipv6local(ifc, ia, 0, np->src)) {
if(arpenter(icmp->f, V6, np->src, np->lnaddr, 8*np->olen-2, ia, ifc, 0) < 0)
break;
@@ -759,12 +743,6 @@
ipmove(ia, np->target);
icmpna6(icmp->f, ia, (pktflags & Sflag)? np->src: v6allnodesL,
np->target, ifc->mac, pktflags);
- break;
- case Tunitent:
- /*
- * not clear what needs to be done. send up
- * an icmp mesg saying don't use this address?
- */
break;
}
freeblist(bp);
--- a/sys/src/9/ip/ip.h
+++ b/sys/src/9/ip/ip.h
@@ -668,6 +668,7 @@
extern void arpcontinue(Arp*, Arpent *a);
extern Block* arpresolve(Arp*, Arpent *a, uchar *mac, Routehint *rh);
extern int arpenter(Fs*, int version, uchar *ip, uchar *mac, int n, uchar *ia, Ipifc *ifc, int refresh);
+extern int arpforme(Fs*, int version, uchar *targ, uchar *src, Ipifc *ifc);
extern void ndpsendsol(Fs*, Arpent*);
/*
@@ -725,7 +726,6 @@
extern int ipv6local(Ipifc *ifc, uchar *local, int prefixlen, uchar *remote);
extern Iplifc* iplocalonifc(Ipifc *ifc, uchar *ip);
extern Iplifc* ipremoteonifc(Ipifc *ifc, uchar *ip);
-extern int ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip);
extern Ipmulti* ipifcgetmulti(Fs *f, Ipifc *ifc, uchar *ma);
extern void ipifcremmulti(Conv *c, uchar *ma, uchar *ia);
extern void ipifcaddmulti(Conv *c, uchar *ma, uchar *ia);
--- a/sys/src/9/ip/ipifc.c
+++ b/sys/src/9/ip/ipifc.c
@@ -569,7 +569,7 @@
addselfcache(f, ifc, lifc, ip, Runi);
- /* register proxy */
+ /* register point-to-point proxy */
if(type & Rptpt){
if(type & Rproxy)
ipifcregisterproxy(f, ifc, rem, 1);
@@ -576,6 +576,10 @@
goto done;
}
+ /* register local ip if proxy */
+ if(type & Rproxy)
+ ipifcregisterproxy(f, ifc, ip, 1);
+
if(type & Rv4) {
/* add subnet directed broadcast address to the self cache */
for(i = 0; i < IPaddrlen; i++)
@@ -667,7 +671,7 @@
lifc->remote, lifc->type, ifc, tifc);
}
- /* unregister proxy */
+ /* unregister point-to-point proxy */
if(lifc->type & Rptpt){
if(lifc->type & Rproxy)
ipifcregisterproxy(f, ifc, lifc->remote, 0);
@@ -674,6 +678,10 @@
goto done;
}
+ /* unregister local ip if proxy */
+ if(lifc->type & Rproxy)
+ ipifcregisterproxy(f, ifc, lifc->local, 0);
+
/* remove route for all nodes multicast */
if((lifc->type & Rv4) == 0){
if(ipcmp(lifc->local, v6loopback) == 0){
@@ -902,6 +910,7 @@
Ipself *p;
int h;
+ if(type == Runi) type |= (lifc->type & Rproxy);
type |= (lifc->type & Rv4);
qlock(f->self);
@@ -1448,22 +1457,6 @@
return lifc;
return nil;
-}
-
-/*
- * See if we're proxying for this address on this interface
- */
-int
-ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
-{
- Route *r;
-
- /* see if this is a direct connected pt to pt address */
- r = v6lookup(f, ip, ip, nil);
- if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
- return 0;
-
- return ipremoteonifc(ifc, ip) != nil;
}
/*
--- a/sys/src/9/ip/ipv6.h
+++ b/sys/src/9/ip/ipv6.h
@@ -94,10 +94,6 @@
TARG_UNI = 2,
TARG_MULTI = 3,
- Tunitent = 1,
- Tuniproxy = 2,
- Tunirany = 3,
-
/* Node constants */
MAX_MULTICAST_SOLICIT = 3,
RETRANS_TIMER = 1000,