diff --git a/src/arp.c b/src/arp.c index 453ab2df..4b894e27 100644 --- a/src/arp.c +++ b/src/arp.c @@ -173,12 +173,24 @@ arp_found(struct arp_state *astate, const struct arp_msg *amsg) * the other IPv4LL client will receieve two ARP * messages. * If another conflict happens within DEFEND_INTERVAL - * then we must drop our address and negotiate a new one. */ + * then we must drop our address and negotiate a new one. + * If DHCPCD_ARP_PERSISTDEFENCE is set, that enables + * RFC5227 section 2.4.c behaviour. Upon conflict + * detection, the host records the time that the + * conflicting ARP packet was received, and then + * broadcasts one single ARP Announcement. The host then + * continues to use the address normally. All further + * conflict notifications within the DEFEND_INTERVAL are + * ignored. */ clock_gettime(CLOCK_MONOTONIC, &now); if (timespecisset(&astate->defend) && eloop_timespec_diff(&now, &astate->defend, NULL) < DEFEND_INTERVAL) + { logwarnx("%s: %d second defence failed for %s", ifp->name, DEFEND_INTERVAL, inet_ntoa(astate->addr)); + if (ifp->options->options & DHCPCD_ARP_PERSISTDEFENCE) + return; + } else if (arp_request(astate, &astate->addr) == -1) logerr(__func__); else { diff --git a/src/dhcpcd.conf.5.in b/src/dhcpcd.conf.5.in index 878cdb8e..d6f73eac 100644 --- a/src/dhcpcd.conf.5.in +++ b/src/dhcpcd.conf.5.in @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd December 18, 2023 +.Dd December 21, 2023 .Dt DHCPCD.CONF 5 .Os .Sh NAME @@ -510,6 +510,8 @@ adding a new IPv4 address. .It Ic noarp Don't send any ARP requests. This also disables IPv4LL. +.It Ic arp_persistdefence +Keep the IP address even if defence fails upon IP Address conflict. .It Ic noauthrequired Don't require authentication even though we requested it. Also allows FORCERENEW and RECONFIGURE messages without authentication. diff --git a/src/if-options.c b/src/if-options.c index b28e4ee2..c57f6a31 100644 --- a/src/if-options.c +++ b/src/if-options.c @@ -168,6 +168,7 @@ const struct option cf_options[] = { {"link_rcvbuf", required_argument, NULL, O_LINK_RCVBUF}, {"configure", no_argument, NULL, O_CONFIGURE}, {"noconfigure", no_argument, NULL, O_NOCONFIGURE}, + {"arp_persistdefence", no_argument, NULL, O_ARP_PERSISTDEFENCE}, {NULL, 0, NULL, '\0'} }; @@ -2337,6 +2338,9 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, case O_NOCONFIGURE: ifo->options &= ~DHCPCD_CONFIGURE; break; + case O_ARP_PERSISTDEFENCE: + ifo->options |= DHCPCD_ARP_PERSISTDEFENCE; + break; default: return 0; } diff --git a/src/if-options.h b/src/if-options.h index 53914655..d317d370 100644 --- a/src/if-options.h +++ b/src/if-options.h @@ -65,6 +65,7 @@ #define DHCPCD_GATEWAY (1ULL << 3) #define DHCPCD_STATIC (1ULL << 4) #define DHCPCD_DEBUG (1ULL << 5) +#define DHCPCD_ARP_PERSISTDEFENCE (1ULL << 6) #define DHCPCD_LASTLEASE (1ULL << 7) #define DHCPCD_INFORM (1ULL << 8) #define DHCPCD_REQUEST (1ULL << 9) @@ -183,6 +184,7 @@ #define O_CONFIGURE O_BASE + 50 #define O_NOCONFIGURE O_BASE + 51 #define O_RANDOMISE_HWADDR O_BASE + 52 +#define O_ARP_PERSISTDEFENCE O_BASE + 53 extern const struct option cf_options[];