]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/ipcp.c
Nit: use _exit when exec fails and restrict values to 0-255 per POSIX.
[ppp.git] / pppd / ipcp.c
index 5962c4720a39ea6924b383463eaecaf513c73a7f..12bcc61be737f9d50b3ac3a6292f6c3c74d93b71 100644 (file)
@@ -40,7 +40,7 @@
  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define RCSID  "$Id: ipcp.c,v 1.70 2005/08/25 23:59:34 paulus Exp $"
+#define RCSID  "$Id: ipcp.c,v 1.73 2008/05/26 08:33:22 paulus Exp $"
 
 /*
  * TODO:
@@ -72,6 +72,7 @@ ipcp_options ipcp_hisoptions[NUM_PPP];        /* Options that we ack'd */
 u_int32_t netmask = 0;         /* IP netmask to set on interface */
 
 bool   disable_defaultip = 0;  /* Don't use hostname for default IP adrs */
+bool   noremoteip = 0;         /* Let him have no IP address */
 
 /* Hook for a plugin to know when IP protocol has come up */
 void (*ip_up_hook) __P((void)) = NULL;
@@ -218,6 +219,13 @@ static option_t ipcp_option_list[] = {
     { "ipcp-no-address", o_bool, &ipcp_wantoptions[0].neg_addr,
       "Disable IP-Address usage", OPT_A2CLR,
       &ipcp_allowoptions[0].neg_addr },
+#ifdef __linux__
+    { "noremoteip", o_bool, &noremoteip,
+      "Allow peer to have no IP address", 1 },
+#endif
+    { "nosendip", o_bool, &ipcp_wantoptions[0].neg_addr,
+      "Don't send our IP address to peer", OPT_A2CLR,
+      &ipcp_wantoptions[0].old_addrs},
 
     { "IP addresses", o_wild, (void *) &setipaddr,
       "set local and remote IP addresses",
@@ -567,6 +575,14 @@ ipcp_init(unit)
     f->callbacks = &ipcp_callbacks;
     fsm_init(&ipcp_fsm[unit]);
 
+    /*
+     * Some 3G modems use repeated IPCP NAKs as a way of stalling
+     * until they can contact a server on the network, so we increase
+     * the default number of NAKs we accept before we start treating
+     * them as rejects.
+     */
+    f->maxnakloops = 100;
+
     memset(wo, 0, sizeof(*wo));
     memset(ao, 0, sizeof(*ao));
 
@@ -715,7 +731,8 @@ ipcp_cilen(f)
 #define LENCIADDRS(neg)                (neg ? CILEN_ADDRS : 0)
 #define LENCIVJ(neg, old)      (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
 #define LENCIADDR(neg)         (neg ? CILEN_ADDR : 0)
-#define LENCIDNS(neg)          (neg ? (CILEN_ADDR) : 0)
+#define LENCIDNS(neg)          LENCIADDR(neg)
+#define LENCIWINS(neg)         LENCIADDR(neg)
 
     /*
      * First see if we want to change our options to the old
@@ -737,7 +754,9 @@ ipcp_cilen(f)
            LENCIVJ(go->neg_vj, go->old_vj) +
            LENCIADDR(go->neg_addr) +
            LENCIDNS(go->req_dns1) +
-           LENCIDNS(go->req_dns2)) ;
+           LENCIDNS(go->req_dns2) +
+           LENCIWINS(go->winsaddr[0]) +
+           LENCIWINS(go->winsaddr[1])) ;
 }
 
 
@@ -811,6 +830,19 @@ ipcp_addci(f, ucp, lenp)
            neg = 0; \
     }
 
+#define ADDCIWINS(opt, addr) \
+    if (addr) { \
+       if (len >= CILEN_ADDR) { \
+           u_int32_t l; \
+           PUTCHAR(opt, ucp); \
+           PUTCHAR(CILEN_ADDR, ucp); \
+           l = ntohl(addr); \
+           PUTLONG(l, ucp); \
+           len -= CILEN_ADDR; \
+       } else \
+           addr = 0; \
+    }
+
     ADDCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, go->ouraddr,
               go->hisaddr);
 
@@ -823,6 +855,10 @@ ipcp_addci(f, ucp, lenp)
 
     ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
 
+    ADDCIWINS(CI_MS_WINS1, go->winsaddr[0]);
+
+    ADDCIWINS(CI_MS_WINS2, go->winsaddr[1]);
+    
     *lenp -= len;
 }
 
@@ -1117,6 +1153,8 @@ ipcp_nakci(f, p, len, treat_as_reject)
      * on an option that we didn't include in our request packet.
      * If they want to negotiate about IP addresses, we comply.
      * If they want us to ask for compression, we refuse.
+     * If they want us to ask for ms-dns, we do that, since some
+     * peers get huffy if we don't.
      */
     while (len >= CILEN_VOID) {
        GETCHAR(citype, p);
@@ -1159,6 +1197,31 @@ ipcp_nakci(f, p, len, treat_as_reject)
                try.neg_addr = 1;
            no.neg_addr = 1;
            break;
+       case CI_MS_DNS1:
+           if (go->req_dns1 || no.req_dns1 || cilen != CILEN_ADDR)
+               goto bad;
+           GETLONG(l, p);
+           try.dnsaddr[0] = htonl(l);
+           try.req_dns1 = 1;
+           no.req_dns1 = 1;
+           break;
+       case CI_MS_DNS2:
+           if (go->req_dns2 || no.req_dns2 || cilen != CILEN_ADDR)
+               goto bad;
+           GETLONG(l, p);
+           try.dnsaddr[1] = htonl(l);
+           try.req_dns2 = 1;
+           no.req_dns2 = 1;
+           break;
+       case CI_MS_WINS1:
+       case CI_MS_WINS2:
+           if (cilen != CILEN_ADDR)
+               goto bad;
+           GETLONG(l, p);
+           ciaddr1 = htonl(l);
+           if (ciaddr1)
+               try.winsaddr[citype == CI_MS_WINS2] = ciaddr1;
+           break;
        }
        p = next;
     }
@@ -1275,6 +1338,21 @@ ipcp_rejci(f, p, len)
        try.neg = 0; \
     }
 
+#define REJCIWINS(opt, addr) \
+    if (addr && \
+       ((cilen = p[1]) == CILEN_ADDR) && \
+       len >= cilen && \
+       p[0] == opt) { \
+       u_int32_t l; \
+       len -= cilen; \
+       INCPTR(2, p); \
+       GETLONG(l, p); \
+       cilong = htonl(l); \
+       /* Check rejected value. */ \
+       if (cilong != addr) \
+           goto bad; \
+       try.winsaddr[opt == CI_MS_WINS2] = 0; \
+    }
 
     REJCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs,
               go->ouraddr, go->hisaddr);
@@ -1288,6 +1366,10 @@ ipcp_rejci(f, p, len)
 
     REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]);
 
+    REJCIWINS(CI_MS_WINS1, go->winsaddr[0]);
+
+    REJCIWINS(CI_MS_WINS2, go->winsaddr[1]);
+
     /*
      * If there are any remaining CIs, then this packet is bad.
      */
@@ -1581,7 +1663,7 @@ endswitch:
      * option safely.
      */
     if (rc != CONFREJ && !ho->neg_addr && !ho->old_addrs &&
-       wo->req_addr && !reject_if_disagree) {
+       wo->req_addr && !reject_if_disagree && !noremoteip) {
        if (rc == CONFACK) {
            rc = CONFNAK;
            ucp = inp;                  /* reset pointer */
@@ -1641,7 +1723,7 @@ ip_demand_conf(u)
 {
     ipcp_options *wo = &ipcp_wantoptions[u];
 
-    if (wo->hisaddr == 0) {
+    if (wo->hisaddr == 0 && !noremoteip) {
        /* make up an arbitrary address for the peer */
        wo->hisaddr = htonl(0x0a707070 + ifunit);
        wo->accept_remote = 1;
@@ -1667,7 +1749,8 @@ ip_demand_conf(u)
            proxy_arp_set[u] = 1;
 
     notice("local  IP address %I", wo->ouraddr);
-    notice("remote IP address %I", wo->hisaddr);
+    if (wo->hisaddr)
+       notice("remote IP address %I", wo->hisaddr);
 
     return 1;
 }
@@ -1706,14 +1789,19 @@ ipcp_up(f)
        ipcp_close(f->unit, "Could not determine local IP address");
        return;
     }
-    if (ho->hisaddr == 0) {
+    if (ho->hisaddr == 0 && !noremoteip) {
        ho->hisaddr = htonl(0x0a404040 + ifunit);
        warn("Could not determine remote IP address: defaulting to %I",
             ho->hisaddr);
     }
     script_setenv("IPLOCAL", ip_ntoa(go->ouraddr), 0);
-    script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr), 1);
+    if (ho->hisaddr != 0)
+       script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr), 1);
 
+    if (!go->req_dns1)
+           go->dnsaddr[0] = 0;
+    if (!go->req_dns2)
+           go->dnsaddr[1] = 0;
     if (go->dnsaddr[0])
        script_setenv("DNS1", ip_ntoa(go->dnsaddr[0]), 0);
     if (go->dnsaddr[1])
@@ -1726,7 +1814,7 @@ ipcp_up(f)
     /*
      * Check that the peer is allowed to use the IP address it wants.
      */
-    if (!auth_ip_addr(f->unit, ho->hisaddr)) {
+    if (ho->hisaddr != 0 && !auth_ip_addr(f->unit, ho->hisaddr)) {
        error("Peer is not authorized to use remote address %I", ho->hisaddr);
        ipcp_close(f->unit, "Unauthorized remote IP address");
        return;
@@ -1749,7 +1837,7 @@ ipcp_up(f)
                wo->ouraddr = go->ouraddr;
            } else
                script_unsetenv("OLDIPLOCAL");
-           if (ho->hisaddr != wo->hisaddr) {
+           if (ho->hisaddr != wo->hisaddr && wo->hisaddr != 0) {
                warn("Remote IP address changed to %I", ho->hisaddr);
                script_setenv("OLDIPREMOTE", ip_ntoa(wo->hisaddr), 0);
                wo->hisaddr = ho->hisaddr;
@@ -1771,7 +1859,7 @@ ipcp_up(f)
                    default_route_set[f->unit] = 1;
 
            /* Make a proxy ARP entry if requested. */
-           if (ipcp_wantoptions[f->unit].proxy_arp)
+           if (ho->hisaddr != 0 && ipcp_wantoptions[f->unit].proxy_arp)
                if (sifproxyarp(f->unit, ho->hisaddr))
                    proxy_arp_set[f->unit] = 1;
 
@@ -1821,14 +1909,15 @@ ipcp_up(f)
                default_route_set[f->unit] = 1;
 
        /* Make a proxy ARP entry if requested. */
-       if (ipcp_wantoptions[f->unit].proxy_arp)
+       if (ho->hisaddr != 0 && ipcp_wantoptions[f->unit].proxy_arp)
            if (sifproxyarp(f->unit, ho->hisaddr))
                proxy_arp_set[f->unit] = 1;
 
        ipcp_wantoptions[0].ouraddr = go->ouraddr;
 
        notice("local  IP address %I", go->ouraddr);
-       notice("remote IP address %I", ho->hisaddr);
+       if (ho->hisaddr != 0)
+           notice("remote IP address %I", ho->hisaddr);
        if (go->dnsaddr[0])
            notice("primary   DNS address %I", go->dnsaddr[0]);
        if (go->dnsaddr[1])
@@ -2114,7 +2203,7 @@ ipcp_printpkt(p, plen, printer, arg)
            case CI_MS_DNS2:
                p += 2;
                GETLONG(cilong, p);
-               printer(arg, "ms-dns%d %I", code - CI_MS_DNS1 + 1,
+               printer(arg, "ms-dns%d %I", (code == CI_MS_DNS1? 1: 2),
                        htonl(cilong));
                break;
            case CI_MS_WINS1: