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