108 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			108 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 268080fc19990711a1d1e1acd68a50aa2f6cb5fb Mon Sep 17 00:00:00 2001
 | |
| From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
 | |
| Date: Fri, 17 Sep 2021 20:12:21 +0200
 | |
| Subject: [PATCH] Offer alternative DHCPv6 address if requested is taken
 | |
| 
 | |
| In some cases multiple requests might arrive from single DUID. It may
 | |
| happen just one address is offered to different IAID requests. When
 | |
| the first request confirms lease, another would be offered alternative
 | |
| address instead of address in use error.
 | |
| 
 | |
| Includes check on such Rapid commit equivalents and returns NotOnLink
 | |
| error, required by RFC 8145, if requested address were not on any
 | |
| supported prefix.
 | |
| ---
 | |
|  src/rfc3315.c | 39 ++++++++++++++++++++++++++++-----------
 | |
|  1 file changed, 28 insertions(+), 11 deletions(-)
 | |
| 
 | |
| diff --git a/src/rfc3315.c b/src/rfc3315.c
 | |
| index 5c2ff97..d1534ad 100644
 | |
| --- a/src/rfc3315.c
 | |
| +++ b/src/rfc3315.c
 | |
| @@ -614,7 +614,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 | |
|        
 | |
|      case DHCP6SOLICIT:
 | |
|        {
 | |
| -      	int address_assigned = 0;
 | |
| +	int address_assigned = 0, ia_invalid = 0;
 | |
|  	/* tags without all prefix-class tags */
 | |
|  	struct dhcp_netid *solicit_tags;
 | |
|  	struct dhcp_context *c;
 | |
| @@ -697,6 +697,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 | |
|  		    get_context_tag(state, c);
 | |
|  		    address_assigned = 1;
 | |
|  		  }
 | |
| +		else
 | |
| +		  ia_invalid++;
 | |
|  	      }
 | |
|  	    
 | |
|  	    /* Suggest configured address(es) */
 | |
| @@ -782,11 +784,26 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 | |
|  	    tagif = add_options(state, 0);
 | |
|  	  }
 | |
|  	else
 | |
| -	  { 
 | |
| +	  {
 | |
| +	    char *errmsg;
 | |
|  	    /* no address, return error */
 | |
|  	    o1 = new_opt6(OPTION6_STATUS_CODE);
 | |
| -	    put_opt6_short(DHCP6NOADDRS);
 | |
| -	    put_opt6_string(_("no addresses available"));
 | |
| +	    if (state->lease_allocate && ia_invalid)
 | |
| +	      {
 | |
| +		/* RFC 8415, Section 18.3.2:
 | |
| +		   If any of the prefixes of the included addresses are not
 | |
| +		   appropriate for the link to which the client is connected,
 | |
| +		   the server MUST return the IA to the client with a Status
 | |
| +		   Code option with the value NotOnLink. */
 | |
| +		put_opt6_short(DHCP6NOTONLINK);
 | |
| +		errmsg = _("not on link");
 | |
| +	      }
 | |
| +	    else
 | |
| +	      {
 | |
| +		put_opt6_short(DHCP6NOADDRS);
 | |
| +		errmsg = _("no addresses available");
 | |
| +	      }
 | |
| +	    put_opt6_string(errmsg);
 | |
|  	    end_opt6(o1);
 | |
|  
 | |
|  	    /* Some clients will ask repeatedly when we're not giving
 | |
| @@ -795,7 +812,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 | |
|  	    for (c = state->context; c; c = c->current)
 | |
|  	      if (!(c->flags & CONTEXT_RA_STATELESS))
 | |
|  		{
 | |
| -		  log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, _("no addresses available"));
 | |
| +		  log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, errmsg);
 | |
|  		  break;
 | |
|  		}
 | |
|  	  }
 | |
| @@ -831,7 +848,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 | |
|  		 /* If we get a request with an IA_*A without addresses, treat it exactly like
 | |
|  		    a SOLICT with rapid commit set. */
 | |
|  		 save_counter(start);
 | |
| -		 goto request_no_address; 
 | |
| +		 goto request_no_address;
 | |
|  	       }
 | |
|  
 | |
|  	    o = build_ia(state, &t1cntr);
 | |
| @@ -861,11 +878,11 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 | |
|  		      }
 | |
|  		    else if (!check_address(state, &req_addr))
 | |
|  		      {
 | |
| -			/* Address leased to another DUID/IAID */
 | |
| -			o1 = new_opt6(OPTION6_STATUS_CODE);
 | |
| -			put_opt6_short(DHCP6UNSPEC);
 | |
| -			put_opt6_string(_("address in use"));
 | |
| -			end_opt6(o1);
 | |
| +			/* Address leased to another DUID/IAID.
 | |
| +			   Find another address for the client, treat it exactly like
 | |
| +			   a SOLICT with rapid commit set. */
 | |
| +			save_counter(start);
 | |
| +			goto request_no_address;
 | |
|  		      } 
 | |
|  		    else 
 | |
|  		      {
 | |
| -- 
 | |
| 2.31.1
 | |
| 
 |