1/* $OpenBSD: ipcp.c,v 1.6 2019/02/27 04:52:19 denis Exp $ */ 2 3/*- 4 * Copyright (c) 2009 Internet Initiative Japan Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28/**@file 29 * This is an implementation of IPCP. This code is currently implemented 30 * as network service provider, and the peer is forced to obey our proposal. 31 */ 32/* 33 * RFC 1332, 1877 34 */ 35/* $Id: ipcp.c,v 1.6 2019/02/27 04:52:19 denis Exp $ */ 36#include <sys/types.h> 37#include <sys/socket.h> 38#include <sys/time.h> 39#include <netinet/in.h> 40#include <net/if_dl.h> 41#include <arpa/inet.h> 42#include <stdlib.h> 43#include <stdio.h> 44#include <syslog.h> 45#include <string.h> 46#include <event.h> 47 48#include "debugutil.h" 49#include "npppd.h" 50 51#ifdef IPCP_DEBUG 52#define IPCP_DBG(x) fsm_log x 53#define IPCP_ASSERT(x) ASSERT(x) 54#else 55#define IPCP_DBG(x) 56#define IPCP_ASSERT(x) 57#endif 58 59 60#define IPCP_IP_ADDRESSES 1 61#define IPCP_IP_COMP 2 62#define IPCP_IP_ADDRESS 3 63#define IPCP_PRI_DNS 129 /* 0x81 */ 64#define IPCP_PRI_NBNS 130 /* 0x82 */ 65#define IPCP_SEC_DNS 131 /* 0x83 */ 66#define IPCP_SEC_NBNS 132 /* 0x84 */ 67 68#define u32maskcmp(mask, a, b) (((a) & (mask)) == ((b) & (mask))) 69 70static void ipcp_resetci (fsm *); 71static int ipcp_cilen (fsm *); 72static void ipcp_addci (fsm *, u_char *, int *); 73static int ipcp_ackci (fsm *, u_char *, int); 74static int ipcp_nakci (fsm *, u_char *, int); 75static int ipcp_rejci (fsm *, u_char *, int); 76static int ipcp_reqci (fsm *, u_char *, int *, int); 77static void ipcp_open (fsm *); 78static void ipcp_close (fsm *); 79static void ipcp_start (fsm *); 80static void ipcp_stop (fsm *); 81 82static struct fsm_callbacks ipcp_callbacks = { 83 ipcp_resetci, /* Reset our Configuration Information */ 84 ipcp_cilen, /* Length of our Configuration Information */ 85 ipcp_addci, /* Add our Configuration Information */ 86 ipcp_ackci, /* ACK our Configuration Information */ 87 ipcp_nakci, /* NAK our Configuration Information */ 88 ipcp_rejci, /* Reject our Configuration Information */ 89 ipcp_reqci, /* Request peer's Configuration Information */ 90 91 ipcp_open, /* Called when fsm reaches OPENED state */ 92 ipcp_close, /* Called when fsm leaves OPENED state */ 93 ipcp_start, /* Called when we want the lower layer up */ 94 ipcp_stop, /* Called when we want the lower layer down */ 95 NULL, /* Called when Protocol-Reject received */ 96 NULL, /* Retransmission is necessary */ 97 NULL, /* Called to handle LCP-specific codes */ 98 "ipcp" /* String name of protocol */ 99}; 100 101/** 102 * Initialize {@link ::_ipcp IPCP instance }. 103 */ 104void 105ipcp_init(ipcp *_this, npppd_ppp *ppp) 106{ 107 struct tunnconf *conf; 108 109 memset(_this, 0, sizeof(ipcp)); 110 111 _this->ppp = ppp; 112 _this->fsm.ppp = ppp; 113 114 fsm_init(&_this->fsm); 115 116 _this->fsm.callbacks = &ipcp_callbacks; 117 _this->fsm.protocol = PPP_PROTO_NCP | NCP_IPCP; 118 119 conf = ppp_get_tunnconf(ppp); 120 PPP_FSM_CONFIG(&_this->fsm, timeouttime, conf->ipcp_timeout); 121 PPP_FSM_CONFIG(&_this->fsm, maxconfreqtransmits, 122 conf->ipcp_max_configure); 123 PPP_FSM_CONFIG(&_this->fsm, maxtermtransmits, 124 conf->ipcp_max_terminate); 125 PPP_FSM_CONFIG(&_this->fsm, maxnakloops, 126 conf->ipcp_max_nak_loop); 127} 128 129static void 130ipcp_resetci(fsm *f) 131{ 132 IPCP_DBG((f, LOG_DEBUG, "%s", __func__)); 133 if (npppd_prepare_ip(f->ppp->pppd, f->ppp) != 0) { 134 fsm_log(f, LOG_ERR, "failed to assign ip address."); 135 ppp_stop(f->ppp, NULL); 136 } 137} 138 139static int 140ipcp_cilen(fsm *f) 141{ 142 IPCP_DBG((f, LOG_DEBUG, "%s", __func__)); 143 return f->ppp->mru; 144} 145 146static void 147ipcp_addci(fsm *f, u_char *pktp, int *lpktp) 148{ 149 u_char *pktp0; 150 151 IPCP_DBG((f, LOG_DEBUG, "%s", __func__)); 152 pktp0 = pktp; 153 154 PUTCHAR(IPCP_IP_ADDRESS, pktp); 155 PUTCHAR(6, pktp); 156 memcpy(pktp, &f->ppp->ipcp.ip4_our.s_addr, 4); 157 pktp += 4; 158 *lpktp = pktp - pktp0; 159} 160 161 162static int 163ipcp_ackci(fsm *f, u_char *pktp, int lpkt) 164{ 165 IPCP_DBG((f, LOG_DEBUG, "%s", __func__)); 166 /* TODO */ 167 return -1; 168} 169 170static int 171ipcp_nakci(fsm *f, u_char *pktp, int lpkt) 172{ 173 IPCP_DBG((f, LOG_DEBUG, "%s", __func__)); 174 175 fsm_log(f, LOG_INFO, "Peer refused(ConfNak) our ip=%s.", 176 inet_ntoa(f->ppp->ipcp.ip4_our)); 177 fsm_close(f, NULL); 178 return -1; 179} 180 181static int 182ipcp_rejci(fsm *f, u_char *pktp, int lpkt) 183{ 184 IPCP_DBG((f, LOG_DEBUG, "%s", __func__)); 185 186 fsm_log(f, LOG_INFO, "Peer refused(ConfRej) our ip=%s.", 187 inet_ntoa(f->ppp->ipcp.ip4_our)); 188 fsm_close(f, NULL); 189 190 return 0; 191} 192 193static int 194ipcp_reqci(fsm *f, u_char *pktp, int *lpktp, int reject_if_disagree) 195{ 196 int type, len, rcode, lrej, lnak; 197 u_char rejbuf0[256], nakbuf0[256], *nakbuf, *rejbuf, *pktp0; 198 char buf0[256]; 199 struct in_addr ip_addr, *ip_addrp; 200 npppd_ppp *ppp; 201 npppd *_npppd; 202 int ip_address_acked = 0; 203 204 IPCP_DBG((f, LOG_DEBUG, "%s(reject_if_disagree=%d, nakloops=%d)", 205 __func__, reject_if_disagree, f->nakloops)); 206 ppp = f->ppp; 207 _npppd = ppp->pppd; 208 209 nakbuf = nakbuf0; 210 rejbuf = rejbuf0; 211 lrej = 0; 212 lnak = 0; 213 pktp0 = pktp; 214 rcode = -1; 215 216 if (*lpktp > 128) { 217 rcode = CONFREJ; 218 rejbuf = pktp; 219 lrej = *lpktp; 220 goto fail; 221 } 222 223#define remlen() (*lpktp - (pktp - pktp0)) 224 225 ip_address_acked = 0; 226 while (remlen() >= 2) { 227 GETCHAR(type, pktp); 228 GETCHAR(len, pktp); 229 if (len <= 0 || remlen() + 2 < len) 230 goto fail; 231 232 switch (type) { 233 case IPCP_IP_ADDRESS: 234 case IPCP_PRI_DNS: 235 case IPCP_PRI_NBNS: 236 case IPCP_SEC_DNS: 237 case IPCP_SEC_NBNS: 238 if (remlen() < 4) 239 goto fail; 240 GETLONG(ip_addr.s_addr, pktp); 241 ip_addr.s_addr = htonl(ip_addr.s_addr); 242 243 switch (type) { 244 case IPCP_IP_ADDRESS: 245 if (!ppp_ip_assigned(ppp)) { 246 if (npppd_assign_ip_addr(ppp->pppd, ppp, 247 htonl(ip_addr.s_addr)) != 0 && 248 npppd_assign_ip_addr(ppp->pppd, ppp, 249 INADDR_ANY) != 0) { 250 /* 251 * The reason why it call with INADDR_ANY again here 252 * is to adapt the client expecting to fall back into 253 * dynamic allocation when user-select is allowed. 254 */ 255 pktp -= 4; 256 goto do_reject; 257 } 258 strlcpy(buf0, inet_ntoa(ip_addr), 259 sizeof(buf0)); 260 fsm_log(f, LOG_INFO, 261 "IP Address peer=%s our=%s.", buf0, 262 inet_ntoa( 263 ppp->ppp_framed_ip_address)); 264 } 265 266 if (u32maskcmp(ppp->ppp_framed_ip_netmask 267 .s_addr, ip_addr.s_addr, 268 ppp->ppp_framed_ip_address.s_addr)) { 269 /* 270 * In case of assigning network address, it obey 271 * peer's proposal if peer's IP-Address Option is 272 * included in network address to assign. 273 */ 274 ip_addrp = &ip_addr; 275 } else { 276 ip_addrp = &ppp-> 277 ppp_framed_ip_address; 278 } 279 ip_address_acked = 1; 280 break; 281 case IPCP_PRI_DNS: 282 ip_addrp = &ppp->ipcp.dns_pri; break; 283 case IPCP_SEC_DNS: 284 ip_addrp = &ppp->ipcp.dns_sec; break; 285 case IPCP_PRI_NBNS: 286 ip_addrp = &ppp->ipcp.nbns_pri; break; 287 case IPCP_SEC_NBNS: 288 ip_addrp = &ppp->ipcp.nbns_sec; break; 289 default: 290 ip_addrp = NULL; 291 } 292 293 if (ip_addrp == NULL || 294 ip_addrp->s_addr == INADDR_NONE) { 295 pktp -= 4; 296 goto do_reject; 297 } 298 if (ip_addrp->s_addr != ip_addr.s_addr) { 299 if (reject_if_disagree) { 300 pktp -= 4; 301 goto do_reject; 302 } 303 if (lrej > 0) { 304 /* if there is a reject, will send Rej, not send Nak. */ 305 } else { 306 PUTCHAR(type, nakbuf); 307 PUTCHAR(6, nakbuf); 308 PUTLONG(ntohl(ip_addrp->s_addr), 309 nakbuf); 310 lnak += 6; 311 rcode = CONFNAK; 312 } 313 } 314 break; 315 case IPCP_IP_COMP: 316 case IPCP_IP_ADDRESSES: 317 default: 318 fsm_log(f, LOG_DEBUG, "Unhandled Option %02x %d", type, 319 len); 320do_reject: 321 pktp -= 2; 322 memmove(rejbuf + lrej, pktp, len); 323 lrej += len; 324 pktp += len; 325 rcode = CONFREJ; 326 } 327 continue; 328 } 329 if (rcode == -1) 330 rcode = CONFACK; 331 332fail: 333 switch (rcode) { 334 case CONFREJ: 335 IPCP_DBG((f, LOG_DEBUG, "SendConfRej")); 336 memmove(pktp0, rejbuf0, lrej); 337 *lpktp = lrej; 338 break; 339 case CONFNAK: 340 /* 341 * In case of Yamaha router is set "pp ppp ipcp ip-address off", 342 * it sends ConfReq without IP-Address Option. 343 * To quote RFC 1332: 344 * If negotiation about the remote IP-address is required, and 345 * the peer did not provide the option in its Configure-Request, 346 * the option SHOULD be appended to a Configure-Nak. 347 * 348 * Is any problem of overrunning 6 bytes of lpkt? 349 * - In ppp.c, lpkt is allocated mru + 64 bytes. lpkt is less 350 * than mru, so +6 is enough. 351 */ 352 if (!ip_address_acked) { 353 /* It is mandatory to assign IP address. */ 354 if (!ppp_ip_assigned(ppp)) { 355 if (npppd_assign_ip_addr(ppp->pppd, ppp, 356 INADDR_ANY) != 0) { 357 /* The log already put in npppd_assign_ip_addr(). */ 358 } 359 } 360 PUTCHAR(IPCP_IP_ADDRESS, nakbuf); 361 PUTCHAR(6, nakbuf); 362 PUTLONG(ntohl(ppp->ppp_framed_ip_address.s_addr), 363 nakbuf); 364 lnak += 6; 365 } 366 IPCP_DBG((f, LOG_DEBUG, "SendConfNak")); 367 memmove(pktp0, nakbuf0, lnak); 368 *lpktp = lnak; 369 break; 370 case CONFACK: 371 IPCP_DBG((f, LOG_DEBUG, "SendConfAck")); 372 break; 373 } 374 375 return rcode; 376#undef remlen 377} 378 379static void 380ipcp_open(fsm *f) 381{ 382 if (!ppp_ip_assigned(f->ppp)) { 383 fsm_log(f, LOG_INFO, "the ip-address option from the peer was " 384 "not agreed."); 385 /* 386 * agreed without IP-Address Option. try to assign static address. 387 */ 388 if (f->ppp->realm_framed_ip_address.s_addr 389 != INADDR_USER_SELECT && 390 f->ppp->realm_framed_ip_address.s_addr 391 != INADDR_NAS_SELECT && 392 f->ppp->realm_framed_ip_address.s_addr != 0) { 393 npppd_assign_ip_addr(f->ppp->pppd, f->ppp, INADDR_ANY); 394 } 395 } 396 if (!ppp_ip_assigned(f->ppp)) { 397 fsm_log(f, LOG_NOTICE, 398 "IPCP opened but no IP address for the peer."); 399 ppp_stop(f->ppp, NULL); 400 return; 401 } 402 403 fsm_log(f, LOG_INFO, "logtype=Opened ip=%s assignType=%s", 404 inet_ntoa(f->ppp->ppp_framed_ip_address), 405 (f->ppp->assign_dynapool)? "dynamic" : "static"); 406 407 ppp_ipcp_opened(f->ppp); 408} 409 410static void 411ipcp_close(fsm *f) 412{ 413 IPCP_DBG((f, LOG_DEBUG, "%s", __func__)); 414} 415 416static void 417ipcp_start(fsm *f) 418{ 419} 420 421static void 422ipcp_stop(fsm *f) 423{ 424 fsm_log(f, LOG_INFO, "IPCP is stopped"); 425 ppp_stop(f->ppp, NULL); 426} 427