On Mon, Nov 08, 2021 at 11:52:52AM +0100, Bjorn Ketelaars wrote:
> Diff below does two things:
> 1. add PPP IPCP extensions for name server addresses (rfc1877) to
>    sppp(4)
> 2. propose negotiated name servers from sppp(4) to resolvd(8) using
>    RTM_PROPOSAL_STATIC route messages.
> 
> With this I'm able to use DNS servers as provided by my ISP who uses
> PPPoE. resolv.conf is updated by resolvd(8) as function of status
> changes of pppoe(4).
> 
> rfc1877 implementation is derived from code from NetBSD, and inspired by
> [0] and [1]. Borrowed code from umb(4) for the route messages.
> 
> Opinions/comments/OK?
> 
> 
> [0] https://marc.info/?l=openbsd-tech&m=134943767022961&w=2
> [1] https://marc.info/?l=openbsd-tech&m=159405677416423&w=2
> 
> 
> diff --git sys/net/if_sppp.h sys/net/if_sppp.h
> index ff559fcc369..f2dab61e46b 100644
> --- sys/net/if_sppp.h
> +++ sys/net/if_sppp.h
> @@ -132,6 +132,8 @@ struct sipcp {
>                                 * original one here, in network byte order */
>       u_int32_t req_hisaddr;  /* remote address requested (IPv4) */
>       u_int32_t req_myaddr;   /* local address requested (IPv4) */
> +#define IPCP_MAX_DNSSRV      2
> +     u_int32_t dns[IPCP_MAX_DNSSRV]; /* IPv4  DNS servers (RFC 1877) */

I would very much prefer to use struct in_addr here (or maybe in_addr_t).
It makes it more clear what the data is.

>  #ifdef INET6
>       struct in6_aliasreq req_ifid;   /* local ifid requested (IPv6) */
>  #endif
> diff --git sys/net/if_spppsubr.c sys/net/if_spppsubr.c
> index ac1dc9a709d..225ad8f5a3e 100644
> --- sys/net/if_spppsubr.c
> +++ sys/net/if_spppsubr.c
> @@ -132,6 +132,10 @@
>  #define IPCP_OPT_ADDRESSES   1       /* both IP addresses; deprecated */
>  #define IPCP_OPT_COMPRESSION 2       /* IP compression protocol (VJ) */
>  #define IPCP_OPT_ADDRESS     3       /* local IP address */
> +#define IPCP_OPT_PRIMDNS     129     /* primary remote dns address */
> +#define _IPCP_OPT_PRIMDNS_   4       /* set/check option */
> +#define IPCP_OPT_SECDNS              131     /* secondary remote dns address 
> */
> +#define _IPCP_OPT_SECDNS_    5       /* set/check option */

As kn@ noted this underscore version is a bit rough.
I wonder if IPCP_OPT definitions (from the standard) should be decoupled
from the bitmask values to enable/disable a feature.

  
>  #define IPV6CP_OPT_IFID              1       /* interface identifier */
>  #define IPV6CP_OPT_COMPRESSION       2       /* IPv6 compression protocol */
> @@ -338,6 +342,8 @@ void sppp_update_gw(struct ifnet *ifp);
>  void sppp_set_ip_addrs(void *);
>  void sppp_clear_ip_addrs(void *);
>  void sppp_set_phase(struct sppp *sp);
> +void sppp_update_dns(struct ifnet *ifp);
> +void sppp_rtrequest(struct ifnet *ifp, int req, struct rtentry *rt);
>  
>  /* our control protocol descriptors */
>  static const struct cp lcp = {
> @@ -701,6 +707,7 @@ sppp_attach(struct ifnet *ifp)
>  
>       sp->pp_if.if_type = IFT_PPP;
>       sp->pp_if.if_output = sppp_output;
> +     sp->pp_if.if_rtrequest = sppp_rtrequest;
>       ifq_set_maxlen(&sp->pp_if.if_snd, 50);
>       mq_init(&sp->pp_cpq, 50, IPL_NET);
>       sp->pp_loopcnt = 0;
> @@ -2519,6 +2526,12 @@ sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header 
> *h, int len)
>                       sp->ipcp.opts &= ~(1 << IPCP_OPT_COMPRESS);
>                       break;
>  #endif
> +             case IPCP_OPT_PRIMDNS:
> +                     sp->ipcp.opts &= ~(1 << _IPCP_OPT_PRIMDNS_);
> +                     break;
> +             case IPCP_OPT_SECDNS:
> +                     sp->ipcp.opts &= ~(1 << _IPCP_OPT_SECDNS_);
> +                     break;
>               }
>       }
>       if (debug)
> @@ -2584,6 +2597,16 @@ sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header 
> *h, int len)
>                        */
>                       break;
>  #endif
> +             case IPCP_OPT_PRIMDNS:
> +                     if (len >= 6 && p[1] == 6)
> +                             sp->ipcp.dns[0] = p[2] << 24 | p[3] << 16 |
> +                                 p[4] << 8 | p[5];

Please use memcpy and here. Since this remains in network byte order it
should just work.

> +                     break;
> +             case IPCP_OPT_SECDNS:
> +                     if (len >= 6 && p[1] == 6)
> +                             sp->ipcp.dns[1] = p[2] << 24 | p[3] << 16 |
> +                                 p[4] << 8 | p[5];

See above.

> +                     break;
>               }
>       }
>       if (debug)
> @@ -2612,6 +2635,7 @@ sppp_ipcp_tls(struct sppp *sp)
>           IPCP_MYADDR_DYN|IPCP_HISADDR_DYN);
>       sp->ipcp.req_myaddr = 0;
>       sp->ipcp.req_hisaddr = 0;
> +     memset(&sp->ipcp.dns, 0, sizeof sp->ipcp.dns);
>  
>       sppp_get_ip_addrs(sp, &myaddr, &hisaddr, 0);
>       /*
> @@ -2644,6 +2668,10 @@ sppp_ipcp_tls(struct sppp *sp)
>               sp->ipcp.flags |= IPCP_HISADDR_DYN;
>       }
>  
> +     /* negotiate name server addresses */
> +     sp->ipcp.opts |= (1 << _IPCP_OPT_PRIMDNS_);
> +     sp->ipcp.opts |= (1 << _IPCP_OPT_SECDNS_);
> +
>       /* indicate to LCP that it must stay alive */
>       sp->lcp.protos |= (1 << IDX_IPCP);
>  }
> @@ -2663,7 +2691,7 @@ sppp_ipcp_tlf(struct sppp *sp)
>  void
>  sppp_ipcp_scr(struct sppp *sp)
>  {
> -     char opt[6 /* compression */ + 6 /* address */];
> +     char opt[6 /* compression */ + 6 /* address */ + 12 /* dns addresses 
> */];

This line is too long now. I feel this should be documented in a different
way.

>       u_int32_t ouraddr;
>       int i = 0;
>  
> @@ -2692,6 +2720,24 @@ sppp_ipcp_scr(struct sppp *sp)
>               opt[i++] = ouraddr;
>       }
>  
> +     if (sp->ipcp.opts & (1 << _IPCP_OPT_PRIMDNS_)) {
> +             opt[i++] = IPCP_OPT_PRIMDNS;
> +             opt[i++] = 6;
> +             opt[i++] = sp->ipcp.dns[0] >> 24;
> +             opt[i++] = sp->ipcp.dns[0] >> 16;
> +             opt[i++] = sp->ipcp.dns[0] >> 8;
> +             opt[i++] = sp->ipcp.dns[0];

Again this calls for memcpy()

> +     }
> +
> +     if (sp->ipcp.opts & (1 << _IPCP_OPT_SECDNS_)) {
> +             opt[i++] = IPCP_OPT_SECDNS;
> +             opt[i++] = 6;
> +             opt[i++] = sp->ipcp.dns[1] >> 24;
> +             opt[i++] = sp->ipcp.dns[1] >> 16;
> +             opt[i++] = sp->ipcp.dns[1] >> 8;
> +             opt[i++] = sp->ipcp.dns[1];
> +     }
> +
>       sp->confid[IDX_IPCP] = ++sp->pp_seq;
>       sppp_cp_send(sp, PPP_IPCP, CONF_REQ, sp->confid[IDX_IPCP], i, opt);
>  }
> @@ -4242,6 +4288,7 @@ sppp_set_ip_addrs(void *arg1)
>                       goto out;
>               }
>               sppp_update_gw(ifp);
> +             sppp_update_dns(ifp);
>       }
>  out:
>       NET_UNLOCK();
> @@ -4302,6 +4349,9 @@ sppp_clear_ip_addrs(void *arg1)
>                       goto out;
>               }
>               sppp_update_gw(ifp);
> +
> +             memset(sp->ipcp.dns, 0, sizeof(sp->ipcp.dns));
> +             sppp_update_dns(ifp);
>       }
>  out:
>       NET_UNLOCK();
> @@ -4721,6 +4771,8 @@ sppp_ipcp_opt_name(u_char opt)
>       case IPCP_OPT_ADDRESSES:        return "addresses";
>       case IPCP_OPT_COMPRESSION:      return "compression";
>       case IPCP_OPT_ADDRESS:          return "address";
> +     case IPCP_OPT_PRIMDNS:          return "primdns";
> +     case IPCP_OPT_SECDNS:           return "secdns";
>       }
>       snprintf (buf, sizeof buf, "0x%x", opt);
>       return buf;
> @@ -4851,3 +4903,45 @@ sppp_set_phase(struct sppp *sp)
>               if_link_state_change(ifp);
>       }
>  }
> +
> +void
> +sppp_update_dns(struct ifnet *ifp)
> +{
> +     struct rt_addrinfo info;
> +     struct sockaddr_rtdns rtdns;
> +     struct sppp *sp = ifp->if_softc;
> +     u_int32_t dns;
> +     int i, flag = 0;
> +     size_t sz = 0;
> +
> +     memset(&rtdns, 0, sizeof(rtdns));
> +     memset(&info, 0, sizeof(info));
> +
> +     for (i = 0; i < IPCP_MAX_DNSSRV; i++) {
> +             dns = ntohl(sp->ipcp.dns[i]);
> +             if (dns == INADDR_ANY)
> +                     break;
> +             sz = sizeof(dns);
> +             memcpy(rtdns.sr_dns + i * sz, &dns, sz);
> +             flag = RTF_UP;
> +     }
> +
> +     rtdns.sr_family = AF_INET;
> +     rtdns.sr_len = 2 + i * sz;
> +     info.rti_info[RTAX_DNS] = srtdnstosa(&rtdns);
> +
> +     rtm_proposal(ifp, &info, flag, RTP_PROPOSAL_STATIC);
> +}
> +
> +void
> +sppp_rtrequest(struct ifnet *ifp, int req, struct rtentry *rt)
> +{
> +     if (req == RTM_PROPOSAL) {
> +             KERNEL_LOCK();
> +             sppp_update_dns(ifp);
> +             KERNEL_UNLOCK();
> +             return;
> +     }
> +
> +     p2p_rtrequest(ifp, req, rt);
> +}
> 

Apart from that good work :)

-- 
:wq Claudio

Reply via email to