2 * Copyright (c) 1982, 1986, 1988, 1993
3 * The Regents of the University of California.
4 * Copyright (c) 2005 Andre Oppermann, Internet Business Solutions AG.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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 * 4. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
35 #include "opt_ipstealth.h"
37 #include <sys/param.h>
38 #include <sys/systm.h>
40 #include <sys/domain.h>
41 #include <sys/protosw.h>
42 #include <sys/socket.h>
44 #include <sys/kernel.h>
45 #include <sys/syslog.h>
46 #include <sys/sysctl.h>
49 #include <net/if_types.h>
50 #include <net/if_var.h>
51 #include <net/if_dl.h>
52 #include <net/route.h>
53 #include <net/netisr.h>
56 #include <netinet/in.h>
57 #include <netinet/in_fib.h>
58 #include <netinet/in_systm.h>
59 #include <netinet/in_var.h>
60 #include <netinet/ip.h>
61 #include <netinet/in_pcb.h>
62 #include <netinet/ip_var.h>
63 #include <netinet/ip_options.h>
64 #include <netinet/ip_icmp.h>
65 #include <machine/in_cksum.h>
67 #include <sys/socketvar.h>
69 static VNET_DEFINE(int, ip_dosourceroute
);
70 SYSCTL_INT(_net_inet_ip
, IPCTL_SOURCEROUTE
, sourceroute
,
71 CTLFLAG_VNET
| CTLFLAG_RW
, &VNET_NAME(ip_dosourceroute
), 0,
72 "Enable forwarding source routed IP packets");
73 #define V_ip_dosourceroute VNET(ip_dosourceroute)
75 static VNET_DEFINE(int, ip_acceptsourceroute
);
76 SYSCTL_INT(_net_inet_ip
, IPCTL_ACCEPTSOURCEROUTE
, accept_sourceroute
,
77 CTLFLAG_VNET
| CTLFLAG_RW
, &VNET_NAME(ip_acceptsourceroute
), 0,
78 "Enable accepting source routed IP packets");
79 #define V_ip_acceptsourceroute VNET(ip_acceptsourceroute)
81 VNET_DEFINE(int, ip_doopts
) = 1; /* 0 = ignore, 1 = process, 2 = reject */
82 SYSCTL_INT(_net_inet_ip
, OID_AUTO
, process_options
, CTLFLAG_VNET
| CTLFLAG_RW
,
83 &VNET_NAME(ip_doopts
), 0, "Enable IP options processing ([LS]SRR, RR, TS)");
85 static void save_rte(struct mbuf
*m
, u_char
*, struct in_addr
);
88 * Do option processing on a datagram, possibly discarding it if bad options
89 * are encountered, or forwarding it if source-routed.
91 * The pass argument is used when operating in the IPSTEALTH mode to tell
92 * what options to process: [LS]SRR (pass 0) or the others (pass 1). The
93 * reason for as many as two passes is that when doing IPSTEALTH, non-routing
94 * options should be processed only if the packet is for us.
96 * Returns 1 if packet has been forwarded/freed, 0 if the packet should be
100 ip_dooptions(struct mbuf
*m
, int pass
)
102 struct ip
*ip
= mtod(m
, struct ip
*);
104 struct in_ifaddr
*ia
;
105 int opt
, optlen
, cnt
, off
, code
, type
= ICMP_PARAMPROB
, forward
= 0;
106 struct in_addr
*sin
, dst
;
108 struct nhop4_extended nh_ext
;
109 struct sockaddr_in ipaddr
= { sizeof(ipaddr
), AF_INET
};
111 /* Ignore or reject packets with IP options. */
112 if (V_ip_doopts
== 0)
114 else if (V_ip_doopts
== 2) {
116 code
= ICMP_UNREACH_FILTER_PROHIB
;
121 cp
= (u_char
*)(ip
+ 1);
122 cnt
= (ip
->ip_hl
<< 2) - sizeof (struct ip
);
123 for (; cnt
> 0; cnt
-= optlen
, cp
+= optlen
) {
124 opt
= cp
[IPOPT_OPTVAL
];
125 if (opt
== IPOPT_EOL
)
127 if (opt
== IPOPT_NOP
)
130 if (cnt
< IPOPT_OLEN
+ sizeof(*cp
)) {
131 code
= &cp
[IPOPT_OLEN
] - (u_char
*)ip
;
134 optlen
= cp
[IPOPT_OLEN
];
135 if (optlen
< IPOPT_OLEN
+ sizeof(*cp
) || optlen
> cnt
) {
136 code
= &cp
[IPOPT_OLEN
] - (u_char
*)ip
;
146 * Source routing with record. Find interface with current
147 * destination address. If none on this machine then drop if
148 * strictly routed, or do nothing if loosely routed. Record
149 * interface address and bring up next address component. If
150 * strictly routed make sure next address is on directly
156 if (V_ipstealth
&& pass
> 0)
159 if (optlen
< IPOPT_OFFSET
+ sizeof(*cp
)) {
160 code
= &cp
[IPOPT_OLEN
] - (u_char
*)ip
;
163 if ((off
= cp
[IPOPT_OFFSET
]) < IPOPT_MINOFF
) {
164 code
= &cp
[IPOPT_OFFSET
] - (u_char
*)ip
;
167 ipaddr
.sin_addr
= ip
->ip_dst
;
168 if (ifa_ifwithaddr_check((struct sockaddr
*)&ipaddr
)
170 if (opt
== IPOPT_SSRR
) {
172 code
= ICMP_UNREACH_SRCFAIL
;
175 if (!V_ip_dosourceroute
)
176 goto nosourcerouting
;
178 * Loose routing, and not at next destination
179 * yet; nothing to do except forward.
183 off
--; /* 0 origin */
184 if (off
> optlen
- (int)sizeof(struct in_addr
)) {
186 * End of source route. Should be for us.
188 if (!V_ip_acceptsourceroute
)
189 goto nosourcerouting
;
190 save_rte(m
, cp
, ip
->ip_src
);
197 if (!V_ip_dosourceroute
) {
198 if (V_ipforwarding
) {
199 char buf
[16]; /* aaa.bbb.ccc.ddd\0 */
201 * Acting as a router, so generate
205 strcpy(buf
, inet_ntoa(ip
->ip_dst
));
207 "attempted source route from %s to %s\n",
208 inet_ntoa(ip
->ip_src
), buf
);
210 code
= ICMP_UNREACH_SRCFAIL
;
214 * Not acting as a router, so
220 IPSTAT_INC(ips_cantforward
);
227 * locate outgoing interface
229 (void)memcpy(&ipaddr
.sin_addr
, cp
+ off
,
230 sizeof(ipaddr
.sin_addr
));
233 code
= ICMP_UNREACH_SRCFAIL
;
235 if (opt
== IPOPT_SSRR
) {
236 #define INA struct in_ifaddr *
237 #define SA struct sockaddr *
238 ia
= (INA
)ifa_ifwithdstaddr((SA
)&ipaddr
,
241 ia
= (INA
)ifa_ifwithnet((SA
)&ipaddr
, 0,
246 memcpy(cp
+ off
, &(IA_SIN(ia
)->sin_addr
),
247 sizeof(struct in_addr
));
248 ifa_free(&ia
->ia_ifa
);
250 /* XXX MRT 0 for routing */
251 if (fib4_lookup_nh_ext(M_GETFIB(m
),
252 ipaddr
.sin_addr
, 0, 0, &nh_ext
) != 0)
255 memcpy(cp
+ off
, &nh_ext
.nh_src
,
256 sizeof(struct in_addr
));
259 ip
->ip_dst
= ipaddr
.sin_addr
;
260 cp
[IPOPT_OFFSET
] += sizeof(struct in_addr
);
262 * Let ip_intr's mcast routing check handle mcast pkts
264 forward
= !IN_MULTICAST(ntohl(ip
->ip_dst
.s_addr
));
269 if (V_ipstealth
&& pass
== 0)
272 if (optlen
< IPOPT_OFFSET
+ sizeof(*cp
)) {
273 code
= &cp
[IPOPT_OFFSET
] - (u_char
*)ip
;
276 if ((off
= cp
[IPOPT_OFFSET
]) < IPOPT_MINOFF
) {
277 code
= &cp
[IPOPT_OFFSET
] - (u_char
*)ip
;
281 * If no space remains, ignore.
283 off
--; /* 0 origin */
284 if (off
> optlen
- (int)sizeof(struct in_addr
))
286 (void)memcpy(&ipaddr
.sin_addr
, &ip
->ip_dst
,
287 sizeof(ipaddr
.sin_addr
));
289 * Locate outgoing interface; if we're the
290 * destination, use the incoming interface (should be
293 if ((ia
= (INA
)ifa_ifwithaddr((SA
)&ipaddr
)) != NULL
) {
294 memcpy(cp
+ off
, &(IA_SIN(ia
)->sin_addr
),
295 sizeof(struct in_addr
));
296 ifa_free(&ia
->ia_ifa
);
297 } else if (fib4_lookup_nh_ext(M_GETFIB(m
),
298 ipaddr
.sin_addr
, 0, 0, &nh_ext
) == 0) {
299 memcpy(cp
+ off
, &nh_ext
.nh_src
,
300 sizeof(struct in_addr
));
303 code
= ICMP_UNREACH_HOST
;
306 cp
[IPOPT_OFFSET
] += sizeof(struct in_addr
);
311 if (V_ipstealth
&& pass
== 0)
314 code
= cp
- (u_char
*)ip
;
315 if (optlen
< 4 || optlen
> 40) {
316 code
= &cp
[IPOPT_OLEN
] - (u_char
*)ip
;
319 if ((off
= cp
[IPOPT_OFFSET
]) < 5) {
320 code
= &cp
[IPOPT_OLEN
] - (u_char
*)ip
;
323 if (off
> optlen
- (int)sizeof(int32_t)) {
324 cp
[IPOPT_OFFSET
+ 1] += (1 << 4);
325 if ((cp
[IPOPT_OFFSET
+ 1] & 0xf0) == 0) {
326 code
= &cp
[IPOPT_OFFSET
] - (u_char
*)ip
;
331 off
--; /* 0 origin */
332 sin
= (struct in_addr
*)(cp
+ off
);
333 switch (cp
[IPOPT_OFFSET
+ 1] & 0x0f) {
335 case IPOPT_TS_TSONLY
:
338 case IPOPT_TS_TSANDADDR
:
339 if (off
+ sizeof(uint32_t) +
340 sizeof(struct in_addr
) > optlen
) {
341 code
= &cp
[IPOPT_OFFSET
] - (u_char
*)ip
;
344 ipaddr
.sin_addr
= dst
;
345 ia
= (INA
)ifaof_ifpforaddr((SA
)&ipaddr
,
349 (void)memcpy(sin
, &IA_SIN(ia
)->sin_addr
,
350 sizeof(struct in_addr
));
351 ifa_free(&ia
->ia_ifa
);
352 cp
[IPOPT_OFFSET
] += sizeof(struct in_addr
);
353 off
+= sizeof(struct in_addr
);
356 case IPOPT_TS_PRESPEC
:
357 if (off
+ sizeof(uint32_t) +
358 sizeof(struct in_addr
) > optlen
) {
359 code
= &cp
[IPOPT_OFFSET
] - (u_char
*)ip
;
362 (void)memcpy(&ipaddr
.sin_addr
, sin
,
363 sizeof(struct in_addr
));
364 if (ifa_ifwithaddr_check((SA
)&ipaddr
) == 0)
366 cp
[IPOPT_OFFSET
] += sizeof(struct in_addr
);
367 off
+= sizeof(struct in_addr
);
371 code
= &cp
[IPOPT_OFFSET
+ 1] - (u_char
*)ip
;
375 (void)memcpy(cp
+ off
, &ntime
, sizeof(uint32_t));
376 cp
[IPOPT_OFFSET
] += sizeof(uint32_t);
379 if (forward
&& V_ipforwarding
) {
385 icmp_error(m
, type
, code
, 0, 0);
386 IPSTAT_INC(ips_badoptions
);
391 * Save incoming source route for use in replies, to be picked up later by
392 * ip_srcroute if the receiver is interested.
395 save_rte(struct mbuf
*m
, u_char
*option
, struct in_addr dst
)
398 struct ipopt_tag
*opts
;
400 opts
= (struct ipopt_tag
*)m_tag_get(PACKET_TAG_IPOPTIONS
,
401 sizeof(struct ipopt_tag
), M_NOWAIT
);
405 olen
= option
[IPOPT_OLEN
];
406 if (olen
> sizeof(opts
->ip_srcrt
) - (1 + sizeof(dst
))) {
407 m_tag_free((struct m_tag
*)opts
);
410 bcopy(option
, opts
->ip_srcrt
.srcopt
, olen
);
411 opts
->ip_nhops
= (olen
- IPOPT_OFFSET
- 1) / sizeof(struct in_addr
);
412 opts
->ip_srcrt
.dst
= dst
;
413 m_tag_prepend(m
, (struct m_tag
*)opts
);
417 * Retrieve incoming source route for use in replies, in the same form used
418 * by setsockopt. The first hop is placed before the options, will be
422 ip_srcroute(struct mbuf
*m0
)
424 struct in_addr
*p
, *q
;
426 struct ipopt_tag
*opts
;
428 opts
= (struct ipopt_tag
*)m_tag_find(m0
, PACKET_TAG_IPOPTIONS
, NULL
);
432 if (opts
->ip_nhops
== 0)
434 m
= m_get(M_NOWAIT
, MT_DATA
);
438 #define OPTSIZ (sizeof(opts->ip_srcrt.nop) + sizeof(opts->ip_srcrt.srcopt))
440 /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
441 m
->m_len
= opts
->ip_nhops
* sizeof(struct in_addr
) +
442 sizeof(struct in_addr
) + OPTSIZ
;
445 * First, save first hop for return route.
447 p
= &(opts
->ip_srcrt
.route
[opts
->ip_nhops
- 1]);
448 *(mtod(m
, struct in_addr
*)) = *p
--;
451 * Copy option fields and padding (nop) to mbuf.
453 opts
->ip_srcrt
.nop
= IPOPT_NOP
;
454 opts
->ip_srcrt
.srcopt
[IPOPT_OFFSET
] = IPOPT_MINOFF
;
455 (void)memcpy(mtod(m
, caddr_t
) + sizeof(struct in_addr
),
456 &(opts
->ip_srcrt
.nop
), OPTSIZ
);
457 q
= (struct in_addr
*)(mtod(m
, caddr_t
) +
458 sizeof(struct in_addr
) + OPTSIZ
);
461 * Record return path as an IP source route, reversing the path
462 * (pointers are now aligned).
464 while (p
>= opts
->ip_srcrt
.route
) {
468 * Last hop goes to final destination.
470 *q
= opts
->ip_srcrt
.dst
;
471 m_tag_delete(m0
, (struct m_tag
*)opts
);
476 * Strip out IP options, at higher level protocol in the kernel.
479 ip_stripoptions(struct mbuf
*m
)
481 struct ip
*ip
= mtod(m
, struct ip
*);
484 olen
= (ip
->ip_hl
<< 2) - sizeof(struct ip
);
486 if (m
->m_flags
& M_PKTHDR
)
487 m
->m_pkthdr
.len
-= olen
;
488 ip
->ip_len
= htons(ntohs(ip
->ip_len
) - olen
);
489 ip
->ip_hl
= sizeof(struct ip
) >> 2;
491 bcopy((char *)ip
+ sizeof(struct ip
) + olen
, (ip
+ 1),
492 (size_t )(m
->m_len
- sizeof(struct ip
)));
496 * Insert IP options into preformed packet. Adjust IP destination as
497 * required for IP source routing, as indicated by a non-zero in_addr at the
498 * start of the options.
500 * XXX This routine assumes that the packet has no options in place.
503 ip_insertoptions(struct mbuf
*m
, struct mbuf
*opt
, int *phlen
)
505 struct ipoption
*p
= mtod(opt
, struct ipoption
*);
507 struct ip
*ip
= mtod(m
, struct ip
*);
510 optlen
= opt
->m_len
- sizeof(p
->ipopt_dst
);
511 if (optlen
+ ntohs(ip
->ip_len
) > IP_MAXPACKET
) {
513 return (m
); /* XXX should fail */
515 if (p
->ipopt_dst
.s_addr
)
516 ip
->ip_dst
= p
->ipopt_dst
;
517 if (!M_WRITABLE(m
) || M_LEADINGSPACE(m
) < optlen
) {
518 n
= m_gethdr(M_NOWAIT
, MT_DATA
);
524 n
->m_pkthdr
.rcvif
= NULL
;
525 n
->m_pkthdr
.len
+= optlen
;
526 m
->m_len
-= sizeof(struct ip
);
527 m
->m_data
+= sizeof(struct ip
);
530 m
->m_len
= optlen
+ sizeof(struct ip
);
531 m
->m_data
+= max_linkhdr
;
532 bcopy(ip
, mtod(m
, void *), sizeof(struct ip
));
536 m
->m_pkthdr
.len
+= optlen
;
537 bcopy(ip
, mtod(m
, void *), sizeof(struct ip
));
539 ip
= mtod(m
, struct ip
*);
540 bcopy(p
->ipopt_list
, ip
+ 1, optlen
);
541 *phlen
= sizeof(struct ip
) + optlen
;
542 ip
->ip_v
= IPVERSION
;
543 ip
->ip_hl
= *phlen
>> 2;
544 ip
->ip_len
= htons(ntohs(ip
->ip_len
) + optlen
);
549 * Copy options from ip to jp, omitting those not copied during
553 ip_optcopy(struct ip
*ip
, struct ip
*jp
)
556 int opt
, optlen
, cnt
;
558 cp
= (u_char
*)(ip
+ 1);
559 dp
= (u_char
*)(jp
+ 1);
560 cnt
= (ip
->ip_hl
<< 2) - sizeof (struct ip
);
561 for (; cnt
> 0; cnt
-= optlen
, cp
+= optlen
) {
563 if (opt
== IPOPT_EOL
)
565 if (opt
== IPOPT_NOP
) {
566 /* Preserve for IP mcast tunnel's LSRR alignment. */
572 KASSERT(cnt
>= IPOPT_OLEN
+ sizeof(*cp
),
573 ("ip_optcopy: malformed ipv4 option"));
574 optlen
= cp
[IPOPT_OLEN
];
575 KASSERT(optlen
>= IPOPT_OLEN
+ sizeof(*cp
) && optlen
<= cnt
,
576 ("ip_optcopy: malformed ipv4 option"));
578 /* Bogus lengths should have been caught by ip_dooptions. */
581 if (IPOPT_COPIED(opt
)) {
582 bcopy(cp
, dp
, optlen
);
586 for (optlen
= dp
- (u_char
*)(jp
+1); optlen
& 0x3; optlen
++)
592 * Set up IP options in pcb for insertion in output packets. Store in mbuf
593 * with pointer in pcbopt, adding pseudo-option with destination address if
597 ip_pcbopts(struct inpcb
*inp
, int optname
, struct mbuf
*m
)
601 struct mbuf
**pcbopt
;
604 INP_WLOCK_ASSERT(inp
);
606 pcbopt
= &inp
->inp_options
;
608 /* turn off any old options */
610 (void)m_free(*pcbopt
);
612 if (m
== NULL
|| m
->m_len
== 0) {
614 * Only turning off any previous options.
621 if (m
->m_len
% sizeof(int32_t))
624 * IP first-hop destination address will be stored before actual
625 * options; move other options back and clear it when none present.
627 if (m
->m_data
+ m
->m_len
+ sizeof(struct in_addr
) >= &m
->m_dat
[MLEN
])
630 m
->m_len
+= sizeof(struct in_addr
);
631 cp
= mtod(m
, u_char
*) + sizeof(struct in_addr
);
632 bcopy(mtod(m
, void *), cp
, (unsigned)cnt
);
633 bzero(mtod(m
, void *), sizeof(struct in_addr
));
635 for (; cnt
> 0; cnt
-= optlen
, cp
+= optlen
) {
636 opt
= cp
[IPOPT_OPTVAL
];
637 if (opt
== IPOPT_EOL
)
639 if (opt
== IPOPT_NOP
)
642 if (cnt
< IPOPT_OLEN
+ sizeof(*cp
))
644 optlen
= cp
[IPOPT_OLEN
];
645 if (optlen
< IPOPT_OLEN
+ sizeof(*cp
) || optlen
> cnt
)
656 * User process specifies route as:
660 * D must be our final destination (but we can't
661 * check that since we may not have connected yet).
662 * A is first hop destination, which doesn't appear
663 * in actual IP option, but is stored before the
666 /* XXX-BZ PRIV_NETINET_SETHDROPTS? */
667 if (optlen
< IPOPT_MINOFF
- 1 + sizeof(struct in_addr
))
669 m
->m_len
-= sizeof(struct in_addr
);
670 cnt
-= sizeof(struct in_addr
);
671 optlen
-= sizeof(struct in_addr
);
672 cp
[IPOPT_OLEN
] = optlen
;
674 * Move first hop before start of options.
676 bcopy((caddr_t
)&cp
[IPOPT_OFFSET
+1], mtod(m
, caddr_t
),
677 sizeof(struct in_addr
));
679 * Then copy rest of options back
680 * to close up the deleted entry.
682 bcopy((&cp
[IPOPT_OFFSET
+1] + sizeof(struct in_addr
)),
684 (unsigned)cnt
- (IPOPT_MINOFF
- 1));
688 if (m
->m_len
> MAX_IPOPTLEN
+ sizeof(struct in_addr
))
699 * Check for the presence of the IP Router Alert option [RFC2113]
700 * in the header of an IPv4 datagram.
702 * This call is not intended for use from the forwarding path; it is here
703 * so that protocol domains may check for the presence of the option.
704 * Given how FreeBSD's IPv4 stack is currently structured, the Router Alert
705 * option does not have much relevance to the implementation, though this
706 * may change in future.
707 * Router alert options SHOULD be passed if running in IPSTEALTH mode and
708 * we are not the endpoint.
709 * Length checks on individual options should already have been performed
710 * by ip_dooptions() therefore they are folded under INVARIANTS here.
712 * Return zero if not present or options are invalid, non-zero if present.
715 ip_checkrouteralert(struct mbuf
*m
)
717 struct ip
*ip
= mtod(m
, struct ip
*);
719 int opt
, optlen
, cnt
, found_ra
;
722 cp
= (u_char
*)(ip
+ 1);
723 cnt
= (ip
->ip_hl
<< 2) - sizeof (struct ip
);
724 for (; cnt
> 0; cnt
-= optlen
, cp
+= optlen
) {
725 opt
= cp
[IPOPT_OPTVAL
];
726 if (opt
== IPOPT_EOL
)
728 if (opt
== IPOPT_NOP
)
732 if (cnt
< IPOPT_OLEN
+ sizeof(*cp
))
735 optlen
= cp
[IPOPT_OLEN
];
737 if (optlen
< IPOPT_OLEN
+ sizeof(*cp
) || optlen
> cnt
)
744 if (optlen
!= IPOPT_OFFSET
+ sizeof(uint16_t) ||
745 (*((uint16_t *)&cp
[IPOPT_OFFSET
]) != 0))