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) */
 #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 */
 
 #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];
+                       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];
+                       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 
*/];
        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];
+       }
+
+       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);
+}

Reply via email to