1 /* command interface to Pluto
2 * Copyright (C) 1997 Angelos D. Keromytis.
3 * Copyright (C) 1998-2001 D. Hugh Redelmeier.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 #include <sys/types.h>
24 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
33 #include <utils/optionsfrom.h>
35 #include "constants.h"
39 static void help(void)
44 " [--optionsfrom <filename>]"
53 " --name <connection_name>"
56 " [--tunnelipv4 | --tunnelipv6]"
58 " (--host <ip-address> | --id <identity>)"
61 " [--ca <distinguished name>]"
62 " [--sendcert <policy>]"
64 " [--groups <access control groups>]"
66 " [--ikeport <port-number>]"
67 " [--nexthop <ip-address>]"
68 " [--srcip <ip-address>]"
70 " [--client <subnet> | --clientwithin <address range>]"
71 " [--clientprotoport <protocol>/<port>]"
74 " [--updown <updown>]"
77 " (--host <ip-address> | --id <identity>)"
80 " [--ca <distinguished name>]"
81 " [--sendcert <policy>]"
83 " [--ikeport <port-number>]"
84 " [--nexthop <ip-address>]"
85 " [--srcip <ip-address>]"
87 " [--client <subnet> | --clientwithin <address range>]"
88 " [--clientprotoport <protocol>/<port>]"
91 " [--updown <updown>]"
101 " [--ikelifetime <seconds>]"
102 " [--ipseclifetime <seconds>]"
104 " [--reykeymargin <seconds>]"
105 " [--reykeyfuzz <percentage>]"
107 " [--keyingtries <count>]"
109 " [--esp <esp-algos>]"
113 " [--dpdaction (none|clear|hold|restart)]"
115 " [--dpddelay <seconds> --dpdtimeout <seconds>]"
117 " [--initiateontraffic|--pass|--drop|--reject]"
119 " [--failnone|--failpass|--faildrop|--failreject]"
122 " (--route | --unroute)"
123 " --name <connection_name>"
128 " (--initiate | --terminate)"
129 " --name <connection_name>"
132 "opportunistic initiation: whack"
133 " [--tunnelipv4 | --tunnelipv6]"
135 " --oppohere <ip-address>"
136 " --oppothere <ip-address>"
140 " (--name <connection_name> | --caname <ca name>)"
143 " --deletestate <state_object_number>"
144 " --crash <ip-address>"
149 " [--pubkeyrsa <key>]"
158 " [--ldaphost <hostname>]"
159 " [--ldapbase <base>]"
164 " [--strictcrlpolicy]"
167 "debug: whack [--name <connection_name>]"
175 " [--debug-emitting]"
178 " [--debug-lifecycle]"
184 " [--debug-controlmore]"
188 "leases: whack --leases"
189 " [--name <connection_name>]"
190 " [--lease-addr <ip-address> | --lease-id <identity>]"
193 " (--listen | --unlisten)"
195 "list: whack [--utc]"
220 " [--rereadocspcerts]"
226 " [--name <connection_name>] --status|--statusall"
229 " --scencrypt|scdecrypt <value>"
231 " [--outbase <base>]"
237 "strongSwan "VERSION
"\n");
240 static const char *label
= NULL
; /* --label operand, saved for diagnostics */
242 static const char *name
= NULL
; /* --name operand, saved for diagnostics */
244 /* options read by optionsfrom */
248 * exit whack after cleaning up
250 static void whack_exit(int status
)
252 options
->destroy(options
);
257 * print a string as a diagnostic, then exit whack unhappily
259 static void diag(const char *mess
)
263 fprintf(stderr
, "whack error: ");
266 fprintf(stderr
, "%s ", label
);
270 fprintf(stderr
, "\"%s\" ", name
);
272 fprintf(stderr
, "%s\n", mess
);
274 whack_exit(RC_WHACK_PROBLEM
);
277 /* conditially calls diag; prints second arg, if non-NULL, as quoted string */
278 static void diagq(err_t ugh
, const char *this)
288 char buf
[120]; /* arbitrary limit */
290 snprintf(buf
, sizeof(buf
), "%s \"%s\"", ugh
, this);
296 /* complex combined operands return one of these enumerated values
297 * Note: these become flags in an lset_t. Since there are more than
298 * 32, we partition them into:
299 * - OPT_* options (most random options)
300 * - LST_* options (list various internal data)
301 * - DBGOPT_* option (DEBUG options)
302 * - END_* options (End description options)
303 * - CD_* options (Connection Description options)
304 * - CA_* options (CA description options)
307 # define OPT_FIRST OPT_CTLBASE
353 # define OPT_LAST OPT_ASYNC /* last "normal" option */
355 /* Smartcard options */
357 # define SC_FIRST SC_ENCRYPT /* first smartcard option */
364 # define SC_LAST SC_OUTBASE /* last "smartcard" option */
368 # define LST_FIRST LST_UTC /* first list option */
384 # define LST_LAST LST_ALL /* last list option */
386 /* Connection End Description options */
388 # define END_FIRST END_HOST /* first end description */
405 #define END_LAST END_UPDOWN /* last end description*/
407 /* Connection Description options -- segregated */
409 # define CD_FIRST CD_TO /* first connection description */
412 # define CD_POLICY_FIRST CD_PSK
413 CD_PSK
, /* same order as POLICY_* */
414 CD_RSASIG
, /* same order as POLICY_* */
415 CD_ENCRYPT
, /* same order as POLICY_* */
416 CD_AUTHENTICATE
, /* same order as POLICY_* */
417 CD_COMPRESS
, /* same order as POLICY_* */
418 CD_TUNNEL
, /* same order as POLICY_* */
419 CD_PFS
, /* same order as POLICY_* */
420 CD_DISABLEARRIVALCHECK
, /* same order as POLICY_* */
421 CD_SHUNT0
, /* same order as POLICY_* */
422 CD_SHUNT1
, /* same order as POLICY_* */
423 CD_FAIL0
, /* same order as POLICY_* */
424 CD_FAIL1
, /* same order as POLICY_* */
425 CD_DONT_REKEY
, /* same order as POLICY_* */
444 # define CD_LAST CD_ESP /* last connection description */
446 /* Certificate Authority (CA) description options */
448 # define CA_FIRST CA_NAME /* first ca description */
459 # define CA_LAST CA_STRICT /* last ca description */
461 #ifdef DEBUG /* must be last so others are less than 32 to fit in lset_t */
462 # define DBGOPT_FIRST DBGOPT_NONE
464 /* NOTE: these definitions must match DBG_* and IMPAIR_* in constants.h */
468 DBGOPT_RAW
, /* same order as DBG_* */
469 DBGOPT_CRYPT
, /* same order as DBG_* */
470 DBGOPT_PARSING
, /* same order as DBG_* */
471 DBGOPT_EMITTING
, /* same order as DBG_* */
472 DBGOPT_CONTROL
, /* same order as DBG_* */
473 DBGOPT_LIFECYCLE
, /* same order as DBG_* */
474 DBGOPT_KERNEL
, /* same order as DBG_* */
475 DBGOPT_DNS
, /* same order as DBG_* */
476 DBGOPT_NATT
, /* same order as DBG_* */
477 DBGOPT_OPPO
, /* same order as DBG_* */
478 DBGOPT_CONTROLMORE
, /* same order as DBG_* */
480 DBGOPT_PRIVATE
, /* same order as DBG_* */
482 DBGOPT_IMPAIR_DELAY_ADNS_KEY_ANSWER
, /* same order as IMPAIR_* */
483 DBGOPT_IMPAIR_DELAY_ADNS_TXT_ANSWER
, /* same order as IMPAIR_* */
484 DBGOPT_IMPAIR_BUST_MI2
, /* same order as IMPAIR_* */
485 DBGOPT_IMPAIR_BUST_MR2
/* same order as IMPAIR_* */
487 # define DBGOPT_LAST DBGOPT_IMPAIR_BUST_MR2
492 /* Carve up space for result from getop_long.
493 * Stupidly, the only result is an int.
494 * Numeric arg is bit immediately left of basic value.
497 #define OPTION_OFFSET 256 /* to get out of the way of letter options */
498 #define NUMERIC_ARG (1 << 9) /* expect a numeric argument */
499 #define AUX_SHIFT 10 /* amount to shift for aux information */
501 static const struct option long_opts
[] = {
502 # define OO OPTION_OFFSET
503 /* name, has_arg, flag, val */
505 { "help", no_argument
, NULL
, 'h' },
506 { "version", no_argument
, NULL
, 'v' },
507 { "optionsfrom", required_argument
, NULL
, '+' },
508 { "label", required_argument
, NULL
, 'l' },
510 { "ctlbase", required_argument
, NULL
, OPT_CTLBASE
+ OO
},
511 { "name", required_argument
, NULL
, OPT_NAME
+ OO
},
513 { "keyid", required_argument
, NULL
, OPT_KEYID
+ OO
},
514 { "addkey", no_argument
, NULL
, OPT_ADDKEY
+ OO
},
515 { "pubkeyrsa", required_argument
, NULL
, OPT_PUBKEYRSA
+ OO
},
517 { "myid", required_argument
, NULL
, OPT_MYID
+ OO
},
519 { "route", no_argument
, NULL
, OPT_ROUTE
+ OO
},
520 { "unroute", no_argument
, NULL
, OPT_UNROUTE
+ OO
},
522 { "initiate", no_argument
, NULL
, OPT_INITIATE
+ OO
},
523 { "terminate", no_argument
, NULL
, OPT_TERMINATE
+ OO
},
524 { "delete", no_argument
, NULL
, OPT_DELETE
+ OO
},
525 { "deletestate", required_argument
, NULL
, OPT_DELETESTATE
+ OO
+ NUMERIC_ARG
},
526 { "crash", required_argument
, NULL
, OPT_DELETECRASH
+ OO
},
527 { "listen", no_argument
, NULL
, OPT_LISTEN
+ OO
},
528 { "unlisten", no_argument
, NULL
, OPT_UNLISTEN
+ OO
},
530 { "leases", no_argument
, NULL
, OPT_LEASES
+ OO
},
531 { "lease-addr", required_argument
, NULL
, OPT_LEASEADDR
+ OO
},
532 { "lease-id", required_argument
, NULL
, OPT_LEASEID
+ OO
},
534 { "purgeocsp", no_argument
, NULL
, OPT_PURGEOCSP
+ OO
},
536 { "rereadsecrets", no_argument
, NULL
, OPT_REREADSECRETS
+ OO
},
537 { "rereadcacerts", no_argument
, NULL
, OPT_REREADCACERTS
+ OO
},
538 { "rereadaacerts", no_argument
, NULL
, OPT_REREADAACERTS
+ OO
},
539 { "rereadocspcerts", no_argument
, NULL
, OPT_REREADOCSPCERTS
+ OO
},
540 { "rereadacerts", no_argument
, NULL
, OPT_REREADACERTS
+ OO
},
541 { "rereadcrls", no_argument
, NULL
, OPT_REREADCRLS
+ OO
},
542 { "rereadall", no_argument
, NULL
, OPT_REREADALL
+ OO
},
543 { "status", no_argument
, NULL
, OPT_STATUS
+ OO
},
544 { "statusall", no_argument
, NULL
, OPT_STATUSALL
+ OO
},
545 { "shutdown", no_argument
, NULL
, OPT_SHUTDOWN
+ OO
},
547 { "oppohere", required_argument
, NULL
, OPT_OPPO_HERE
+ OO
},
548 { "oppothere", required_argument
, NULL
, OPT_OPPO_THERE
+ OO
},
550 { "asynchronous", no_argument
, NULL
, OPT_ASYNC
+ OO
},
552 /* smartcard options */
554 { "scencrypt", required_argument
, NULL
, SC_ENCRYPT
+ OO
},
555 { "scdecrypt", required_argument
, NULL
, SC_DECRYPT
+ OO
},
556 { "inbase", required_argument
, NULL
, SC_INBASE
+ OO
},
557 { "outbase", required_argument
, NULL
, SC_OUTBASE
+ OO
},
561 { "utc", no_argument
, NULL
, LST_UTC
+ OO
},
562 { "listalgs", no_argument
, NULL
, LST_ALGS
+ OO
},
563 { "listpubkeys", no_argument
, NULL
, LST_PUBKEYS
+ OO
},
564 { "listcerts", no_argument
, NULL
, LST_CERTS
+ OO
},
565 { "listcacerts", no_argument
, NULL
, LST_CACERTS
+ OO
},
566 { "listacerts", no_argument
, NULL
, LST_ACERTS
+ OO
},
567 { "listaacerts", no_argument
, NULL
, LST_AACERTS
+ OO
},
568 { "listocspcerts", no_argument
, NULL
, LST_OCSPCERTS
+ OO
},
569 { "listgroups", no_argument
, NULL
, LST_GROUPS
+ OO
},
570 { "listcainfos", no_argument
, NULL
, LST_CAINFOS
+ OO
},
571 { "listcrls", no_argument
, NULL
, LST_CRLS
+ OO
},
572 { "listocsp", no_argument
, NULL
, LST_OCSP
+ OO
},
573 { "listcards", no_argument
, NULL
, LST_CARDS
+ OO
},
574 { "listall", no_argument
, NULL
, LST_ALL
+ OO
},
576 /* options for an end description */
578 { "host", required_argument
, NULL
, END_HOST
+ OO
},
579 { "id", required_argument
, NULL
, END_ID
+ OO
},
580 { "cert", required_argument
, NULL
, END_CERT
+ OO
},
581 { "ca", required_argument
, NULL
, END_CA
+ OO
},
582 { "sendcert", required_argument
, NULL
, END_SENDCERT
+ OO
},
583 { "groups", required_argument
, NULL
, END_GROUPS
+ OO
},
584 { "ikeport", required_argument
, NULL
, END_IKEPORT
+ OO
+ NUMERIC_ARG
},
585 { "nexthop", required_argument
, NULL
, END_NEXTHOP
+ OO
},
586 { "client", required_argument
, NULL
, END_CLIENT
+ OO
},
587 { "clientwithin", required_argument
, NULL
, END_CLIENTWITHIN
+ OO
},
588 { "clientprotoport", required_argument
, NULL
, END_CLIENTPROTOPORT
+ OO
},
589 { "dnskeyondemand", no_argument
, NULL
, END_DNSKEYONDEMAND
+ OO
},
590 { "srcip", required_argument
, NULL
, END_SRCIP
+ OO
},
591 { "hostaccess", no_argument
, NULL
, END_HOSTACCESS
+ OO
},
592 { "updown", required_argument
, NULL
, END_UPDOWN
+ OO
},
594 /* options for a connection description */
596 { "to", no_argument
, NULL
, CD_TO
+ OO
},
598 { "psk", no_argument
, NULL
, CD_PSK
+ OO
},
599 { "rsasig", no_argument
, NULL
, CD_RSASIG
+ OO
},
601 { "encrypt", no_argument
, NULL
, CD_ENCRYPT
+ OO
},
602 { "authenticate", no_argument
, NULL
, CD_AUTHENTICATE
+ OO
},
603 { "compress", no_argument
, NULL
, CD_COMPRESS
+ OO
},
604 { "tunnel", no_argument
, NULL
, CD_TUNNEL
+ OO
},
605 { "tunnelipv4", no_argument
, NULL
, CD_TUNNELIPV4
+ OO
},
606 { "tunnelipv6", no_argument
, NULL
, CD_TUNNELIPV6
+ OO
},
607 { "pfs", no_argument
, NULL
, CD_PFS
+ OO
},
608 { "disablearrivalcheck", no_argument
, NULL
, CD_DISABLEARRIVALCHECK
+ OO
},
609 { "initiateontraffic", no_argument
, NULL
610 , CD_SHUNT0
+ (POLICY_SHUNT_TRAP
>> POLICY_SHUNT_SHIFT
<< AUX_SHIFT
) + OO
},
611 { "pass", no_argument
, NULL
612 , CD_SHUNT0
+ (POLICY_SHUNT_PASS
>> POLICY_SHUNT_SHIFT
<< AUX_SHIFT
) + OO
},
613 { "drop", no_argument
, NULL
614 , CD_SHUNT0
+ (POLICY_SHUNT_DROP
>> POLICY_SHUNT_SHIFT
<< AUX_SHIFT
) + OO
},
615 { "reject", no_argument
, NULL
616 , CD_SHUNT0
+ (POLICY_SHUNT_REJECT
>> POLICY_SHUNT_SHIFT
<< AUX_SHIFT
) + OO
},
617 { "failnone", no_argument
, NULL
618 , CD_FAIL0
+ (POLICY_FAIL_NONE
>> POLICY_FAIL_SHIFT
<< AUX_SHIFT
) + OO
},
619 { "failpass", no_argument
, NULL
620 , CD_FAIL0
+ (POLICY_FAIL_PASS
>> POLICY_FAIL_SHIFT
<< AUX_SHIFT
) + OO
},
621 { "faildrop", no_argument
, NULL
622 , CD_FAIL0
+ (POLICY_FAIL_DROP
>> POLICY_FAIL_SHIFT
<< AUX_SHIFT
) + OO
},
623 { "failreject", no_argument
, NULL
624 , CD_FAIL0
+ (POLICY_FAIL_REJECT
>> POLICY_FAIL_SHIFT
<< AUX_SHIFT
) + OO
},
625 { "dontrekey", no_argument
, NULL
, CD_DONT_REKEY
+ OO
},
626 { "ipv4", no_argument
, NULL
, CD_CONNIPV4
+ OO
},
627 { "ipv6", no_argument
, NULL
, CD_CONNIPV6
+ OO
},
629 { "ikelifetime", required_argument
, NULL
, CD_IKELIFETIME
+ OO
+ NUMERIC_ARG
},
630 { "ipseclifetime", required_argument
, NULL
, CD_IPSECLIFETIME
+ OO
+ NUMERIC_ARG
},
631 { "rekeymargin", required_argument
, NULL
, CD_RKMARGIN
+ OO
+ NUMERIC_ARG
},
632 { "rekeywindow", required_argument
, NULL
, CD_RKMARGIN
+ OO
+ NUMERIC_ARG
}, /* OBSOLETE */
633 { "rekeyfuzz", required_argument
, NULL
, CD_RKFUZZ
+ OO
+ NUMERIC_ARG
},
634 { "keyingtries", required_argument
, NULL
, CD_KTRIES
+ OO
+ NUMERIC_ARG
},
635 { "dpdaction", required_argument
, NULL
, CD_DPDACTION
+ OO
},
636 { "dpddelay", required_argument
, NULL
, CD_DPDDELAY
+ OO
+ NUMERIC_ARG
},
637 { "dpdtimeout", required_argument
, NULL
, CD_DPDTIMEOUT
+ OO
+ NUMERIC_ARG
},
638 { "ike", required_argument
, NULL
, CD_IKE
+ OO
},
639 { "pfsgroup", required_argument
, NULL
, CD_PFSGROUP
+ OO
},
640 { "esp", required_argument
, NULL
, CD_ESP
+ OO
},
642 /* options for a ca description */
644 { "caname", required_argument
, NULL
, CA_NAME
+ OO
},
645 { "cacert", required_argument
, NULL
, CA_CERT
+ OO
},
646 { "ldaphost", required_argument
, NULL
, CA_LDAPHOST
+ OO
},
647 { "ldapbase", required_argument
, NULL
, CA_LDAPBASE
+ OO
},
648 { "crluri", required_argument
, NULL
, CA_CRLURI
+ OO
},
649 { "crluri2", required_argument
, NULL
, CA_CRLURI2
+ OO
},
650 { "ocspuri", required_argument
, NULL
, CA_OCSPURI
+ OO
},
651 { "strictcrlpolicy", no_argument
, NULL
, CA_STRICT
+ OO
},
654 { "debug-none", no_argument
, NULL
, DBGOPT_NONE
+ OO
},
655 { "debug-all]", no_argument
, NULL
, DBGOPT_ALL
+ OO
},
656 { "debug-raw", no_argument
, NULL
, DBGOPT_RAW
+ OO
},
657 { "debug-crypt", no_argument
, NULL
, DBGOPT_CRYPT
+ OO
},
658 { "debug-parsing", no_argument
, NULL
, DBGOPT_PARSING
+ OO
},
659 { "debug-emitting", no_argument
, NULL
, DBGOPT_EMITTING
+ OO
},
660 { "debug-control", no_argument
, NULL
, DBGOPT_CONTROL
+ OO
},
661 { "debug-lifecycle", no_argument
, NULL
, DBGOPT_LIFECYCLE
+ OO
},
662 { "debug-klips", no_argument
, NULL
, DBGOPT_KERNEL
+ OO
},
663 { "debug-kernel", no_argument
, NULL
, DBGOPT_KERNEL
+ OO
},
664 { "debug-dns", no_argument
, NULL
, DBGOPT_DNS
+ OO
},
665 { "debug-natt", no_argument
, NULL
, DBGOPT_NATT
+ OO
},
666 { "debug-oppo", no_argument
, NULL
, DBGOPT_OPPO
+ OO
},
667 { "debug-controlmore", no_argument
, NULL
, DBGOPT_CONTROLMORE
+ OO
},
668 { "debug-private", no_argument
, NULL
, DBGOPT_PRIVATE
+ OO
},
670 { "impair-delay-adns-key-answer", no_argument
, NULL
, DBGOPT_IMPAIR_DELAY_ADNS_KEY_ANSWER
+ OO
},
671 { "impair-delay-adns-txt-answer", no_argument
, NULL
, DBGOPT_IMPAIR_DELAY_ADNS_TXT_ANSWER
+ OO
},
672 { "impair-bust-mi2", no_argument
, NULL
, DBGOPT_IMPAIR_BUST_MI2
+ OO
},
673 { "impair-bust-mr2", no_argument
, NULL
, DBGOPT_IMPAIR_BUST_MR2
+ OO
},
679 struct sockaddr_un ctl_addr
= { AF_UNIX
, DEFAULT_CTLBASE CTL_SUFFIX
};
681 /* helper variables and function to encode strings from whack message */
683 static char *next_str
,*str_roof
;
685 static bool pack_str(char **p
)
687 const char *s
= *p
== NULL?
"" : *p
; /* note: NULL becomes ""! */
688 size_t len
= strlen(s
) + 1;
690 if (str_roof
- next_str
< (ptrdiff_t)len
)
692 return FALSE
; /* fishy: no end found */
698 *p
= NULL
; /* don't send pointers on the wire! */
703 static void check_life_time(time_t life
, time_t limit
, const char *which
,
704 const whack_message_t
*msg
)
706 time_t mint
= msg
->sa_rekey_margin
* (100 + msg
->sa_rekey_fuzz
) / 100;
710 char buf
[200]; /* arbitrary limit */
712 snprintf(buf
, sizeof(buf
)
713 , "%s [%lu seconds] must be less than %lu seconds"
714 , which
, (unsigned long)life
, (unsigned long)limit
);
717 if ((msg
->policy
& POLICY_DONT_REKEY
) == LEMPTY
&& life
<= mint
)
719 char buf
[200]; /* arbitrary limit */
721 snprintf(buf
, sizeof(buf
)
722 , "%s [%lu] must be greater than"
723 " rekeymargin*(100+rekeyfuzz)/100 [%lu*(100+%lu)/100 = %lu]"
725 , (unsigned long)life
726 , (unsigned long)msg
->sa_rekey_margin
727 , (unsigned long)msg
->sa_rekey_fuzz
728 , (unsigned long)mint
);
733 static void clear_end(whack_end_t
*e
)
740 e
->host_port
= IKE_UDP_PORT
;
743 static void update_ports(whack_message_t
*m
)
747 if (m
->left
.port
!= 0) {
748 port
= htons(m
->left
.port
);
749 setportof(port
, &m
->left
.host_addr
);
750 setportof(port
, &m
->left
.client
.addr
);
752 if (m
->right
.port
!= 0) {
753 port
= htons(m
->right
.port
);
754 setportof(port
, &m
->right
.host_addr
);
755 setportof(port
, &m
->right
.client
.addr
);
759 static void check_end(whack_end_t
*this, whack_end_t
*that
,
760 bool default_nexthop
, sa_family_t caf
, sa_family_t taf
)
762 if (caf
!= addrtypeof(&this->host_addr
))
763 diag("address family of host inconsistent");
767 if (isanyaddr(&that
->host_addr
))
768 diag("our nexthop must be specified when other host is a %any or %opportunistic");
769 this->host_nexthop
= that
->host_addr
;
772 if (caf
!= addrtypeof(&this->host_nexthop
))
773 diag("address family of nexthop inconsistent");
775 if (this->has_client
)
777 if (taf
!= subnettypeof(&this->client
))
778 diag("address family of client subnet inconsistent");
782 /* fill in anyaddr-anyaddr as (missing) client subnet */
785 diagq(anyaddr(caf
, &cn
), NULL
);
786 diagq(rangetosubnet(&cn
, &cn
, &this->client
), NULL
);
789 /* fill in anyaddr if source IP is not defined */
790 if (!this->has_srcip
)
791 diagq(anyaddr(caf
, &this->host_srcip
), optarg
);
794 if (this->protocol
!= that
->protocol
)
795 diag("the protocol for leftprotoport and rightprotoport must be the same");
798 static void get_secret(int sock
)
800 const char *buf
= NULL
, *secret
;
804 usleep(20000); /* give fflush time for flushing */
806 buf
= getpass("Enter: ");
808 secret
= (buf
== NULL
)?
"" : buf
;
810 /* send the secret to pluto */
811 len
= strlen(secret
) + 1;
812 if (write(sock
, secret
, len
) != len
)
816 fprintf(stderr
, "whack: write() failed (%d %s)\n", e
, strerror(e
));
817 exit(RC_WHACK_PROBLEM
);
821 /* This is a hack for initiating ISAKMP exchanges. */
823 int main(int argc
, char **argv
)
826 char esp_buf
[256]; /* uses snprintf */
834 end_seen_before_to
= LEMPTY
;
837 *tunnel_af_used_by
= NULL
;
839 /* check division of numbering space */
841 assert(OPTION_OFFSET
+ DBGOPT_LAST
< NUMERIC_ARG
);
843 assert(OPTION_OFFSET
+ CA_LAST
< NUMERIC_ARG
);
845 assert(OPT_LAST
- OPT_FIRST
< (sizeof opts_seen
* BITS_PER_BYTE
));
846 assert(SC_LAST
- SC_FIRST
< (sizeof sc_seen
* BITS_PER_BYTE
));
847 assert(LST_LAST
- LST_FIRST
< (sizeof lst_seen
* BITS_PER_BYTE
));
848 assert(END_LAST
- END_FIRST
< (sizeof end_seen
* BITS_PER_BYTE
));
849 assert(CD_LAST
- CD_FIRST
< (sizeof cd_seen
* BITS_PER_BYTE
));
850 assert(CA_LAST
- CA_FIRST
< (sizeof ca_seen
* BITS_PER_BYTE
));
851 #ifdef DEBUG /* must be last so others are less than (sizeof cd_seen * BITS_PER_BYTE) to fit in lset_t */
852 assert(DBGOPT_LAST
- DBGOPT_FIRST
< (sizeof cd_seen
* BITS_PER_BYTE
));
854 /* check that POLICY bit assignment matches with CD_ */
855 assert(LELEM(CD_DONT_REKEY
- CD_POLICY_FIRST
) == POLICY_DONT_REKEY
);
859 clear_end(&msg
.right
); /* left set from this after --to */
863 msg
.keyval
.ptr
= NULL
;
868 /* if a connection is added via whack then we assume IKEv1 */
871 msg
.sa_ike_life_seconds
= OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT
;
872 msg
.sa_ipsec_life_seconds
= PLUTO_SA_LIFE_DURATION_DEFAULT
;
873 msg
.sa_rekey_margin
= SA_REPLACEMENT_MARGIN_DEFAULT
;
874 msg
.sa_rekey_fuzz
= SA_REPLACEMENT_FUZZ_DEFAULT
;
875 msg
.sa_keying_tries
= SA_REPLACEMENT_RETRIES_DEFAULT
;
877 msg
.addr_family
= AF_INET
;
878 msg
.tunnel_addr_family
= AF_INET
;
887 options
= options_create();
892 unsigned long opt_whole
= 0; /* numeric argument for some flags */
894 /* Note: we don't like the way short options get parsed
895 * by getopt_long, so we simply pass an empty string as
896 * the list. It could be "hp:d:c:o:eatfs" "NARXPECK".
898 int c
= getopt_long(argc
, argv
, "", long_opts
, &long_index
) - OPTION_OFFSET
;
901 /* decode a numeric argument, if expected */
909 opt_whole
= strtoul(optarg
, &endptr
, 0);
911 if (*endptr
!= '\0' || endptr
== optarg
)
912 diagq("badly formed numeric argument", optarg
);
914 if (c
>= (1 << AUX_SHIFT
))
916 aux
= c
>> AUX_SHIFT
;
917 c
-= aux
<< AUX_SHIFT
;
921 /* per-class option processing */
922 if (0 <= c
&& c
<= OPT_LAST
)
924 /* OPT_* options get added to opts_seen.
925 * Reject repeated options (unless later code intervenes).
930 diagq("duplicated flag", long_opts
[long_index
].name
);
933 else if (SC_FIRST
<= c
&& c
<= SC_LAST
)
935 /* SC_* options get added to sc_seen.
936 * Reject repeated options (unless later code intervenes).
938 lset_t f
= LELEM(c
- SC_FIRST
);
941 diagq("duplicated flag", long_opts
[long_index
].name
);
944 else if (LST_FIRST
<= c
&& c
<= LST_LAST
)
946 /* LST_* options get added to lst_seen.
947 * Reject repeated options (unless later code intervenes).
949 lset_t f
= LELEM(c
- LST_FIRST
);
952 diagq("duplicated flag", long_opts
[long_index
].name
);
956 else if (DBGOPT_FIRST
<= c
&& c
<= DBGOPT_LAST
)
958 msg
.whack_options
= TRUE
;
961 else if (END_FIRST
<= c
&& c
<= END_LAST
)
963 /* END_* options are added to end_seen.
964 * Reject repeated options (unless later code intervenes).
966 lset_t f
= LELEM(c
- END_FIRST
);
969 diagq("duplicated flag", long_opts
[long_index
].name
);
971 opts_seen
|= LELEM(OPT_CD
);
973 else if (CD_FIRST
<= c
&& c
<= CD_LAST
)
975 /* CD_* options are added to cd_seen.
976 * Reject repeated options (unless later code intervenes).
978 lset_t f
= LELEM(c
- CD_FIRST
);
981 diagq("duplicated flag", long_opts
[long_index
].name
);
983 opts_seen
|= LELEM(OPT_CD
);
985 else if (CA_FIRST
<= c
&& c
<= CA_LAST
)
987 /* CA_* options are added to ca_seen.
988 * Reject repeated options (unless later code intervenes).
990 lset_t f
= LELEM(c
- CA_FIRST
);
993 diagq("duplicated flag", long_opts
[long_index
].name
);
997 /* Note: "break"ing from switch terminates loop.
998 * most cases should end with "continue".
1002 case EOF
- OPTION_OFFSET
: /* end of flags */
1005 case 0 - OPTION_OFFSET
: /* long option already handled */
1008 case ':' - OPTION_OFFSET
: /* diagnostic already printed by getopt_long */
1009 case '?' - OPTION_OFFSET
: /* diagnostic already printed by getopt_long */
1010 diag(NULL
); /* print no additional diagnostic, but exit sadly */
1011 break; /* not actually reached */
1013 case 'h' - OPTION_OFFSET
: /* --help */
1015 whack_exit(0); /* GNU coding standards say to stop here */
1017 case 'v' - OPTION_OFFSET
: /* --version */
1019 const char **sp
= ipsec_copyright_notice();
1021 printf("strongSwan "VERSION
"\n");
1022 for (; *sp
!= NULL
; sp
++)
1025 whack_exit(0); /* GNU coding standards say to stop here */
1027 case 'l' - OPTION_OFFSET
: /* --label <string> */
1028 label
= optarg
; /* remember for diagnostics */
1031 case '+' - OPTION_OFFSET
: /* --optionsfrom <filename> */
1032 if (!options
->from(options
, optarg
, &argc
, &argv
, optind
))
1034 fprintf(stderr
, "optionsfrom failed");
1035 whack_exit(RC_WHACK_PROBLEM
);
1039 /* the rest of the options combine in complex ways */
1041 case OPT_CTLBASE
: /* --port <ctlbase> */
1042 if (snprintf(ctl_addr
.sun_path
, sizeof(ctl_addr
.sun_path
)
1043 , "%s%s", optarg
, CTL_SUFFIX
) == -1)
1044 diag("<ctlbase>" CTL_SUFFIX
" must be fit in a sun_addr");
1047 case OPT_NAME
: /* --name <connection-name> */
1052 case OPT_KEYID
: /* --keyid <identity> */
1053 msg
.whack_key
= !msg
.whack_sc_op
;
1054 msg
.keyid
= optarg
; /* decoded by Pluto */
1057 case OPT_MYID
: /* --myid <identity> */
1058 msg
.whack_myid
= TRUE
;
1059 msg
.myid
= optarg
; /* decoded by Pluto */
1062 case OPT_ADDKEY
: /* --addkey */
1063 msg
.whack_addkey
= TRUE
;
1066 case OPT_PUBKEYRSA
: /* --pubkeyrsa <key> */
1068 static char keyspace
[RSA_MAX_ENCODING_BYTES
]; /* room for 8K bit key */
1069 char diag_space
[TTODATAV_BUF
];
1070 const char *ugh
= ttodatav(optarg
, 0, 0
1071 , keyspace
, sizeof(keyspace
)
1072 , &msg
.keyval
.len
, diag_space
, sizeof(diag_space
)
1073 , TTODATAV_SPACECOUNTS
);
1077 char ugh_space
[80]; /* perhaps enough space */
1079 snprintf(ugh_space
, sizeof(ugh_space
)
1080 , "RSA public-key data malformed (%s)", ugh
);
1081 diagq(ugh_space
, optarg
);
1083 msg
.pubkey_alg
= PUBKEY_ALG_RSA
;
1084 msg
.keyval
.ptr
= keyspace
;
1088 case OPT_ROUTE
: /* --route */
1089 msg
.whack_route
= TRUE
;
1092 case OPT_UNROUTE
: /* --unroute */
1093 msg
.whack_unroute
= TRUE
;
1096 case OPT_INITIATE
: /* --initiate */
1097 msg
.whack_initiate
= TRUE
;
1100 case OPT_TERMINATE
: /* --terminate */
1101 msg
.whack_terminate
= TRUE
;
1104 case OPT_DELETE
: /* --delete */
1105 msg
.whack_delete
= TRUE
;
1108 case OPT_DELETESTATE
: /* --deletestate <state_object_number> */
1109 msg
.whack_deletestate
= TRUE
;
1110 msg
.whack_deletestateno
= opt_whole
;
1113 case OPT_DELETECRASH
: /* --crash <ip-address> */
1114 msg
.whack_crash
= TRUE
;
1115 tunnel_af_used_by
= long_opts
[long_index
].name
;
1116 diagq(ttoaddr(optarg
, 0, msg
.tunnel_addr_family
, &msg
.whack_crash_peer
), optarg
);
1117 if (isanyaddr(&msg
.whack_crash_peer
))
1118 diagq("0.0.0.0 or 0::0 isn't a valid client address", optarg
);
1121 case OPT_LEASES
: /* --leases */
1122 msg
.whack_leases
= TRUE
;
1125 case OPT_LEASEADDR
: /* --lease-addr <ip-address> */
1126 msg
.whack_lease_ip
= optarg
; /* decoded by Pluto */
1129 case OPT_LEASEID
: /* --lease-id <identity> */
1130 msg
.whack_lease_id
= optarg
; /* decoded by Pluto */
1133 case OPT_LISTEN
: /* --listen */
1134 msg
.whack_listen
= TRUE
;
1137 case OPT_UNLISTEN
: /* --unlisten */
1138 msg
.whack_unlisten
= TRUE
;
1141 case OPT_PURGEOCSP
: /* --purgeocsp */
1142 msg
.whack_purgeocsp
= TRUE
;
1145 case OPT_REREADSECRETS
: /* --rereadsecrets */
1146 case OPT_REREADCACERTS
: /* --rereadcacerts */
1147 case OPT_REREADAACERTS
: /* --rereadaacerts */
1148 case OPT_REREADOCSPCERTS
: /* --rereadocspcerts */
1149 case OPT_REREADACERTS
: /* --rereadacerts */
1150 case OPT_REREADCRLS
: /* --rereadcrls */
1151 msg
.whack_reread
|= LELEM(c
-OPT_REREADSECRETS
);
1154 case OPT_REREADALL
: /* --rereadall */
1155 msg
.whack_reread
= REREAD_ALL
;
1158 case OPT_STATUSALL
: /* --statusall */
1159 msg
.whack_statusall
= TRUE
;
1162 case OPT_STATUS
: /* --status */
1163 msg
.whack_status
= TRUE
;
1166 case OPT_SHUTDOWN
: /* --shutdown */
1167 msg
.whack_shutdown
= TRUE
;
1170 case OPT_OPPO_HERE
: /* --oppohere <ip-address> */
1171 tunnel_af_used_by
= long_opts
[long_index
].name
;
1172 diagq(ttoaddr(optarg
, 0, msg
.tunnel_addr_family
, &msg
.oppo_my_client
), optarg
);
1173 if (isanyaddr(&msg
.oppo_my_client
))
1174 diagq("0.0.0.0 or 0::0 isn't a valid client address", optarg
);
1177 case OPT_OPPO_THERE
: /* --oppohere <ip-address> */
1178 tunnel_af_used_by
= long_opts
[long_index
].name
;
1179 diagq(ttoaddr(optarg
, 0, msg
.tunnel_addr_family
, &msg
.oppo_peer_client
), optarg
);
1180 if (isanyaddr(&msg
.oppo_peer_client
))
1181 diagq("0.0.0.0 or 0::0 isn't a valid client address", optarg
);
1185 msg
.whack_async
= TRUE
;
1188 /* Smartcard options */
1190 case SC_ENCRYPT
: /* --scencrypt <plaintext data> */
1191 case SC_DECRYPT
: /* --scdecrypt <encrypted data> */
1192 msg
.whack_sc_op
= 1 + c
- SC_ENCRYPT
;
1193 msg
.whack_key
= FALSE
;
1194 msg
.sc_data
= optarg
;
1197 case SC_INBASE
: /* --inform <format> */
1198 case SC_OUTBASE
: /* --outform <format> */
1202 if (streq(optarg
, "16") || strcaseeq(optarg
, "hex"))
1204 else if (streq(optarg
, "64") || strcaseeq(optarg
, "base64"))
1206 else if (streq(optarg
, "256") || strcaseeq(optarg
, "text")
1207 || strcaseeq(optarg
, "ascii"))
1210 diagq("not a valid base", optarg
);
1221 case LST_UTC
: /* --utc */
1222 msg
.whack_utc
= TRUE
;
1225 case LST_ALGS
: /* --listalgs */
1226 case LST_PUBKEYS
: /* --listpubkeys */
1227 case LST_CERTS
: /* --listcerts */
1228 case LST_CACERTS
: /* --listcacerts */
1229 case LST_ACERTS
: /* --listacerts */
1230 case LST_AACERTS
: /* --listaacerts */
1231 case LST_OCSPCERTS
: /* --listocspcerts */
1232 case LST_GROUPS
: /* --listgroups */
1233 case LST_CAINFOS
: /* --listcainfos */
1234 case LST_CRLS
: /* --listcrls */
1235 case LST_OCSP
: /* --listocsp */
1236 case LST_CARDS
: /* --listcards */
1237 msg
.whack_list
|= LELEM(c
- LST_ALGS
);
1240 case LST_ALL
: /* --listall */
1241 msg
.whack_list
= LIST_ALL
;
1244 /* Connection Description options */
1246 case END_HOST
: /* --host <ip-address> */
1248 lset_t new_policy
= LEMPTY
;
1250 af_used_by
= long_opts
[long_index
].name
;
1251 diagq(anyaddr(msg
.addr_family
, &msg
.right
.host_addr
), optarg
);
1252 if (streq(optarg
, "%any"))
1255 else if (streq(optarg
, "%opportunistic"))
1257 /* always use tunnel mode; mark as opportunistic */
1258 new_policy
|= POLICY_TUNNEL
| POLICY_OPPO
;
1260 else if (streq(optarg
, "%group"))
1262 /* always use tunnel mode; mark as group */
1263 new_policy
|= POLICY_TUNNEL
| POLICY_GROUP
;
1265 else if (streq(optarg
, "%opportunisticgroup"))
1267 /* always use tunnel mode; mark as opportunistic */
1268 new_policy
|= POLICY_TUNNEL
| POLICY_OPPO
| POLICY_GROUP
;
1272 diagq(ttoaddr(optarg
, 0, msg
.addr_family
1273 , &msg
.right
.host_addr
), optarg
);
1276 msg
.policy
|= new_policy
;
1278 if (new_policy
& (POLICY_OPPO
| POLICY_GROUP
))
1280 if (!LHAS(end_seen
, END_CLIENT
- END_FIRST
))
1282 /* set host to 0.0.0 and --client to 0.0.0.0/0
1283 * or IPV6 equivalent
1287 tunnel_af_used_by
= optarg
;
1288 diagq(anyaddr(msg
.tunnel_addr_family
, &any
), optarg
);
1289 diagq(initsubnet(&any
, 0, '0', &msg
.right
.client
), optarg
);
1291 msg
.right
.has_client
= TRUE
;
1293 if (new_policy
& POLICY_GROUP
)
1295 /* client subnet must not be specified by user:
1296 * it will come from the group's file.
1298 if (LHAS(end_seen
, END_CLIENT
- END_FIRST
))
1299 diag("--host %group clashes with --client");
1301 end_seen
|= LELEM(END_CLIENT
- END_FIRST
);
1303 if (new_policy
& POLICY_OPPO
)
1304 msg
.right
.key_from_DNS_on_demand
= TRUE
;
1307 case END_ID
: /* --id <identity> */
1308 msg
.right
.id
= optarg
; /* decoded by Pluto */
1311 case END_CERT
: /* --cert <path> */
1312 msg
.right
.cert
= optarg
; /* decoded by Pluto */
1315 case END_CA
: /* --ca <distinguished name> */
1316 msg
.right
.ca
= optarg
; /* decoded by Pluto */
1320 if (streq(optarg
, "yes") || streq(optarg
, "always"))
1322 msg
.right
.sendcert
= CERT_ALWAYS_SEND
;
1324 else if (streq(optarg
, "no") || streq(optarg
, "never"))
1326 msg
.right
.sendcert
= CERT_NEVER_SEND
;
1328 else if (streq(optarg
, "ifasked"))
1330 msg
.right
.sendcert
= CERT_SEND_IF_ASKED
;
1334 diagq("whack sendcert value is not legal", optarg
);
1338 case END_GROUPS
:/* --groups <access control groups> */
1339 msg
.right
.groups
= optarg
; /* decoded by Pluto */
1342 case END_IKEPORT
: /* --ikeport <port-number> */
1343 if (opt_whole
<=0 || opt_whole
>= 0x10000)
1344 diagq("<port-number> must be a number between 1 and 65535", optarg
);
1345 msg
.right
.host_port
= opt_whole
;
1348 case END_NEXTHOP
: /* --nexthop <ip-address> */
1349 af_used_by
= long_opts
[long_index
].name
;
1350 if (streq(optarg
, "%direct"))
1351 diagq(anyaddr(msg
.addr_family
1352 , &msg
.right
.host_nexthop
), optarg
);
1354 diagq(ttoaddr(optarg
, 0, msg
.addr_family
1355 , &msg
.right
.host_nexthop
), optarg
);
1358 case END_SRCIP
: /* --srcip <ip-address> */
1359 af_used_by
= long_opts
[long_index
].name
;
1360 if (streq(optarg
, "%modeconfig") || streq(optarg
, "%modecfg"))
1362 msg
.right
.modecfg
= TRUE
;
1366 diagq(ttoaddr(optarg
, 0, msg
.addr_family
1367 , &msg
.right
.host_srcip
), optarg
);
1368 msg
.right
.has_srcip
= TRUE
;
1370 msg
.policy
|= POLICY_TUNNEL
; /* srcip => tunnel */
1373 case END_CLIENT
: /* --client <subnet> */
1374 if (end_seen
& LELEM(END_CLIENTWITHIN
- END_FIRST
))
1375 diag("--client conflicts with --clientwithin");
1376 tunnel_af_used_by
= long_opts
[long_index
].name
;
1377 if ((strlen(optarg
) >= 6 && strncmp(optarg
,"vhost:",6) == 0)
1378 || (strlen(optarg
) >= 5 && strncmp(optarg
,"vnet:",5) == 0))
1380 msg
.right
.virt
= optarg
;
1384 diagq(ttosubnet(optarg
, 0, msg
.tunnel_addr_family
, &msg
.right
.client
), optarg
);
1385 msg
.right
.has_client
= TRUE
;
1387 msg
.policy
|= POLICY_TUNNEL
; /* client => tunnel */
1390 case END_CLIENTWITHIN
: /* --clienwithin <address range> */
1391 if (end_seen
& LELEM(END_CLIENT
- END_FIRST
))
1392 diag("--clientwithin conflicts with --client");
1393 tunnel_af_used_by
= long_opts
[long_index
].name
;
1394 diagq(ttosubnet(optarg
, 0, msg
.tunnel_addr_family
, &msg
.right
.client
), optarg
);
1395 msg
.right
.has_client
= TRUE
;
1396 msg
.policy
|= POLICY_TUNNEL
; /* client => tunnel */
1397 msg
.right
.has_client_wildcard
= TRUE
;
1400 case END_CLIENTPROTOPORT
: /* --clientprotoport <protocol>/<port> */
1401 diagq(ttoprotoport(optarg
, 0, &msg
.right
.protocol
, &msg
.right
.port
1402 , &msg
.right
.has_port_wildcard
), optarg
);
1405 case END_DNSKEYONDEMAND
: /* --dnskeyondemand */
1406 msg
.right
.key_from_DNS_on_demand
= TRUE
;
1409 case END_HOSTACCESS
: /* --hostaccess */
1410 msg
.right
.hostaccess
= TRUE
;
1413 case END_UPDOWN
: /* --updown <updown> */
1414 msg
.right
.updown
= optarg
;
1417 case CD_TO
: /* --to */
1418 /* process right end, move it to left, reset it */
1419 if (!LHAS(end_seen
, END_HOST
- END_FIRST
))
1420 diag("connection missing --host before --to");
1421 msg
.left
= msg
.right
;
1422 clear_end(&msg
.right
);
1423 end_seen_before_to
= end_seen
;
1427 case CD_PSK
: /* --psk */
1428 case CD_RSASIG
: /* --rsasig */
1429 case CD_ENCRYPT
: /* --encrypt */
1430 case CD_AUTHENTICATE
: /* --authenticate */
1431 case CD_COMPRESS
: /* --compress */
1432 case CD_TUNNEL
: /* --tunnel */
1433 case CD_PFS
: /* --pfs */
1434 case CD_DISABLEARRIVALCHECK
: /* --disablearrivalcheck */
1435 case CD_DONT_REKEY
: /* --donotrekey */
1436 msg
.policy
|= LELEM(c
- CD_POLICY_FIRST
);
1439 /* --initiateontraffic
1445 msg
.policy
= (msg
.policy
& ~POLICY_SHUNT_MASK
)
1446 | ((lset_t
)aux
<< POLICY_SHUNT_SHIFT
);
1455 msg
.policy
= (msg
.policy
& ~POLICY_FAIL_MASK
)
1456 | ((lset_t
)aux
<< POLICY_FAIL_SHIFT
);
1459 case CD_IKELIFETIME
: /* --ikelifetime <seconds> */
1460 msg
.sa_ike_life_seconds
= opt_whole
;
1463 case CD_IPSECLIFETIME
: /* --ipseclifetime <seconds> */
1464 msg
.sa_ipsec_life_seconds
= opt_whole
;
1467 case CD_RKMARGIN
: /* --rekeymargin <seconds> */
1468 msg
.sa_rekey_margin
= opt_whole
;
1471 case CD_RKFUZZ
: /* --rekeyfuzz <percentage> */
1472 msg
.sa_rekey_fuzz
= opt_whole
;
1475 case CD_KTRIES
: /* --keyingtries <count> */
1476 msg
.sa_keying_tries
= opt_whole
;
1480 if (streq(optarg
, "none"))
1481 msg
.dpd_action
= DPD_ACTION_NONE
;
1482 else if (streq(optarg
, "clear"))
1483 msg
.dpd_action
= DPD_ACTION_CLEAR
;
1484 else if (streq(optarg
, "hold"))
1485 msg
.dpd_action
= DPD_ACTION_HOLD
;
1486 else if (streq(optarg
, "restart"))
1487 msg
.dpd_action
= DPD_ACTION_RESTART
;
1489 msg
.dpd_action
= DPD_ACTION_UNKNOWN
;
1493 msg
.dpd_delay
= opt_whole
;
1497 msg
.dpd_timeout
= opt_whole
;
1500 case CD_IKE
: /* --ike <ike_alg1,ike_alg2,...> */
1504 case CD_PFSGROUP
: /* --pfsgroup modpXXXX */
1505 msg
.pfsgroup
= optarg
;
1508 case CD_ESP
: /* --esp <esp_alg1,esp_alg2,...> */
1513 if (LHAS(cd_seen
, CD_CONNIPV6
- CD_FIRST
))
1514 diag("--ipv4 conflicts with --ipv6");
1516 /* Since this is the default, the flag is redundant.
1517 * So we don't need to set msg.addr_family
1518 * and we don't need to check af_used_by
1519 * and we don't have to consider defaulting tunnel_addr_family.
1524 if (LHAS(cd_seen
, CD_CONNIPV4
- CD_FIRST
))
1525 diag("--ipv6 conflicts with --ipv4");
1527 if (af_used_by
!= NULL
)
1528 diagq("--ipv6 must precede", af_used_by
);
1530 af_used_by
= long_opts
[long_index
].name
;
1531 msg
.addr_family
= AF_INET6
;
1533 /* Consider defaulting tunnel_addr_family to AF_INET6.
1534 * Do so only if it hasn't yet been specified or used.
1536 if (LDISJOINT(cd_seen
, LELEM(CD_TUNNELIPV4
- CD_FIRST
) | LELEM(CD_TUNNELIPV6
- CD_FIRST
))
1537 && tunnel_af_used_by
== NULL
)
1538 msg
.tunnel_addr_family
= AF_INET6
;
1542 if (LHAS(cd_seen
, CD_TUNNELIPV6
- CD_FIRST
))
1543 diag("--tunnelipv4 conflicts with --tunnelipv6");
1545 if (tunnel_af_used_by
!= NULL
)
1546 diagq("--tunnelipv4 must precede", af_used_by
);
1548 msg
.tunnel_addr_family
= AF_INET
;
1552 if (LHAS(cd_seen
, CD_TUNNELIPV4
- CD_FIRST
))
1553 diag("--tunnelipv6 conflicts with --tunnelipv4");
1555 if (tunnel_af_used_by
!= NULL
)
1556 diagq("--tunnelipv6 must precede", af_used_by
);
1558 msg
.tunnel_addr_family
= AF_INET6
;
1561 case CA_NAME
: /* --caname <name> */
1563 msg
.whack_ca
= TRUE
;
1565 case CA_CERT
: /* --cacert <path> */
1566 msg
.cacert
= optarg
;
1568 case CA_LDAPHOST
: /* --ldaphost <hostname> */
1569 msg
.ldaphost
= optarg
;
1571 case CA_LDAPBASE
: /* --ldapbase <base> */
1572 msg
.ldapbase
= optarg
;
1574 case CA_CRLURI
: /* --crluri <uri> */
1575 msg
.crluri
= optarg
;
1577 case CA_CRLURI2
: /* --crluri2 <uri> */
1578 msg
.crluri2
= optarg
;
1580 case CA_OCSPURI
: /* --ocspuri <uri> */
1581 msg
.ocspuri
= optarg
;
1583 case CA_STRICT
: /* --strictcrlpolicy */
1584 msg
.whack_strict
= TRUE
;
1588 case DBGOPT_NONE
: /* --debug-none */
1589 msg
.debugging
= DBG_NONE
;
1592 case DBGOPT_ALL
: /* --debug-all */
1593 msg
.debugging
|= DBG_ALL
; /* note: does not include PRIVATE */
1596 case DBGOPT_RAW
: /* --debug-raw */
1597 case DBGOPT_CRYPT
: /* --debug-crypt */
1598 case DBGOPT_PARSING
: /* --debug-parsing */
1599 case DBGOPT_EMITTING
: /* --debug-emitting */
1600 case DBGOPT_CONTROL
: /* --debug-control */
1601 case DBGOPT_LIFECYCLE
: /* --debug-lifecycle */
1602 case DBGOPT_KERNEL
: /* --debug-kernel, --debug-klips */
1603 case DBGOPT_DNS
: /* --debug-dns */
1604 case DBGOPT_NATT
: /* --debug-natt */
1605 case DBGOPT_OPPO
: /* --debug-oppo */
1606 case DBGOPT_CONTROLMORE
: /* --debug-controlmore */
1607 case DBGOPT_PRIVATE
: /* --debug-private */
1608 case DBGOPT_IMPAIR_DELAY_ADNS_KEY_ANSWER
: /* --impair-delay-adns-key-answer */
1609 case DBGOPT_IMPAIR_DELAY_ADNS_TXT_ANSWER
: /* --impair-delay-adns-txt-answer */
1610 case DBGOPT_IMPAIR_BUST_MI2
: /* --impair_bust_mi2 */
1611 case DBGOPT_IMPAIR_BUST_MR2
: /* --impair_bust_mr2 */
1612 msg
.debugging
|= LELEM(c
-DBGOPT_RAW
);
1616 assert(FALSE
); /* unknown return value */
1623 /* If you see this message unexpectedly, perhaps the
1624 * case for the previous option ended with "break"
1625 * instead of "continue"
1627 diagq("unexpected argument", argv
[optind
]);
1630 /* For each possible form of the command, figure out if an argument
1631 * suggests whether that form was intended, and if so, whether all
1632 * required information was supplied.
1635 /* check opportunistic initiation simulation request */
1636 switch (opts_seen
& (LELEM(OPT_OPPO_HERE
) | LELEM(OPT_OPPO_THERE
)))
1638 case LELEM(OPT_OPPO_HERE
):
1639 case LELEM(OPT_OPPO_THERE
):
1640 diag("--oppohere and --oppothere must be used together");
1642 case LELEM(OPT_OPPO_HERE
) | LELEM(OPT_OPPO_THERE
):
1643 msg
.whack_oppo_initiate
= TRUE
;
1644 if (LIN(cd_seen
, LELEM(CD_TUNNELIPV4
- CD_FIRST
) | LELEM(CD_TUNNELIPV6
- CD_FIRST
)))
1645 opts_seen
&= ~LELEM(OPT_CD
);
1650 if (LHAS(opts_seen
, OPT_LEASEADDR
) && LHAS(opts_seen
, OPT_LEASEID
))
1652 diag("--lease-addr and --lease-id cannot be used together");
1655 /* check connection description */
1656 if (LHAS(opts_seen
, OPT_CD
))
1658 if (!LHAS(cd_seen
, CD_TO
-CD_FIRST
))
1659 diag("connection description option, but no --to");
1661 if (!LHAS(end_seen
, END_HOST
-END_FIRST
))
1662 diag("connection missing --host after --to");
1664 if (isanyaddr(&msg
.left
.host_addr
)
1665 && isanyaddr(&msg
.right
.host_addr
))
1666 diag("hosts cannot both be 0.0.0.0 or 0::0");
1668 if (msg
.policy
& POLICY_OPPO
)
1670 if ((msg
.policy
& (POLICY_PSK
| POLICY_PUBKEY
)) != POLICY_PUBKEY
)
1671 diag("only PUBKEY is supported for opportunism");
1672 if ((msg
.policy
& POLICY_PFS
) == 0)
1673 diag("PFS required for opportunism");
1674 if ((msg
.policy
& POLICY_ENCRYPT
) == 0)
1675 diag("encryption required for opportunism");
1678 check_end(&msg
.left
, &msg
.right
, !LHAS(end_seen_before_to
, END_NEXTHOP
-END_FIRST
)
1679 , msg
.addr_family
, msg
.tunnel_addr_family
);
1681 check_end(&msg
.right
, &msg
.left
, !LHAS(end_seen
, END_NEXTHOP
-END_FIRST
)
1682 , msg
.addr_family
, msg
.tunnel_addr_family
);
1684 if (subnettypeof(&msg
.left
.client
) != subnettypeof(&msg
.right
.client
))
1685 diag("endpoints clash: one is IPv4 and the other is IPv6");
1687 if (NEVER_NEGOTIATE(msg
.policy
))
1689 /* we think this is just a shunt (because he didn't specify
1690 * a host authentication method). If he didn't specify a
1691 * shunt type, he's probably gotten it wrong.
1693 if ((msg
.policy
& POLICY_SHUNT_MASK
) == POLICY_SHUNT_TRAP
)
1694 diag("non-shunt connection must have --psk or --rsasig or both");
1698 /* not just a shunt: a real ipsec connection */
1699 if ((msg
.policy
& POLICY_ID_AUTH_MASK
) == LEMPTY
)
1700 diag("must specify --rsasig or --psk for a connection");
1702 if (!HAS_IPSEC_POLICY(msg
.policy
)
1703 && (msg
.left
.has_client
|| msg
.right
.has_client
))
1704 diag("must not specify clients for ISAKMP-only connection");
1707 msg
.whack_connection
= TRUE
;
1710 /* decide whether --name is mandatory or forbidden */
1711 if (!LDISJOINT(opts_seen
1712 , LELEM(OPT_ROUTE
) | LELEM(OPT_UNROUTE
)
1713 | LELEM(OPT_INITIATE
) | LELEM(OPT_TERMINATE
)
1714 | LELEM(OPT_DELETE
) | LELEM(OPT_CD
)))
1716 if (!LHAS(opts_seen
, OPT_NAME
) && !msg
.whack_ca
)
1717 diag("missing --name <connection_name>");
1719 else if (!msg
.whack_options
&& !msg
.whack_status
&& !msg
.whack_leases
)
1721 if (LHAS(opts_seen
, OPT_NAME
))
1722 diag("no reason for --name");
1725 if (!LDISJOINT(opts_seen
, LELEM(OPT_PUBKEYRSA
) | LELEM(OPT_ADDKEY
)))
1727 if (!LHAS(opts_seen
, OPT_KEYID
))
1728 diag("--addkey and --pubkeyrsa require --keyid");
1731 if (!(msg
.whack_connection
|| msg
.whack_key
|| msg
.whack_myid
1732 || msg
.whack_delete
|| msg
.whack_deletestate
1733 || msg
.whack_initiate
|| msg
.whack_oppo_initiate
|| msg
.whack_terminate
1734 || msg
.whack_route
|| msg
.whack_unroute
|| msg
.whack_listen
1735 || msg
.whack_unlisten
|| msg
.whack_list
|| msg
.whack_purgeocsp
1736 || msg
.whack_reread
|| msg
.whack_ca
|| msg
.whack_status
1737 || msg
.whack_options
|| msg
.whack_shutdown
|| msg
.whack_sc_op
1738 || msg
.whack_leases
))
1740 diag("no action specified; try --help for hints");
1745 /* tricky quick and dirty check for wild values */
1746 if (msg
.sa_rekey_margin
!= 0
1747 && msg
.sa_rekey_fuzz
* msg
.sa_rekey_margin
* 4 / msg
.sa_rekey_margin
/ 4
1748 != msg
.sa_rekey_fuzz
)
1749 diag("rekeymargin or rekeyfuzz values are so large that they cause oveflow");
1751 check_life_time (msg
.sa_ike_life_seconds
, OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM
1752 , "ikelifetime", &msg
);
1754 check_life_time(msg
.sa_ipsec_life_seconds
, SA_LIFE_DURATION_MAXIMUM
1755 , "ipseclifetime", &msg
);
1757 if (msg
.dpd_action
== DPD_ACTION_UNKNOWN
)
1758 diag("dpdaction must be \"none\", \"clear\", \"hold\" or \"restart\"");
1760 if (msg
.dpd_action
!= DPD_ACTION_NONE
)
1762 if (msg
.dpd_delay
<= 0)
1763 diag("dpddelay must be larger than zero");
1765 if (msg
.dpd_timeout
<= 0)
1766 diag("dpdtimeout must be larger than zero");
1768 if (msg
.dpd_timeout
<= msg
.dpd_delay
)
1769 diag("dpdtimeout must be larger than dpddelay");
1772 /* pack strings for inclusion in message */
1773 next_str
= msg
.string
;
1774 str_roof
= &msg
.string
[sizeof(msg
.string
)];
1776 /* build esp message as esp="<esp>;<pfsgroup>" */
1778 snprintf(esp_buf
, sizeof (esp_buf
), "%s;%s",
1779 msg
.esp ? msg
.esp
: "",
1780 msg
.pfsgroup ? msg
.pfsgroup
: "");
1783 if (!pack_str(&msg
.name
) /* string 1 */
1784 || !pack_str(&msg
.left
.id
) /* string 2 */
1785 || !pack_str(&msg
.left
.cert
) /* string 3 */
1786 || !pack_str(&msg
.left
.ca
) /* string 4 */
1787 || !pack_str(&msg
.left
.groups
) /* string 5 */
1788 || !pack_str(&msg
.left
.updown
) /* string 6 */
1789 || !pack_str(&msg
.left
.sourceip
) /* string 7 */
1790 || !pack_str(&msg
.left
.virt
) /* string 8 */
1791 || !pack_str(&msg
.right
.id
) /* string 9 */
1792 || !pack_str(&msg
.right
.cert
) /* string 10 */
1793 || !pack_str(&msg
.right
.ca
) /* string 11 */
1794 || !pack_str(&msg
.right
.groups
) /* string 12 */
1795 || !pack_str(&msg
.right
.updown
) /* string 13 */
1796 || !pack_str(&msg
.right
.sourceip
) /* string 14 */
1797 || !pack_str(&msg
.right
.virt
) /* string 15 */
1798 || !pack_str(&msg
.keyid
) /* string 16 */
1799 || !pack_str(&msg
.myid
) /* string 17 */
1800 || !pack_str(&msg
.cacert
) /* string 18 */
1801 || !pack_str(&msg
.ldaphost
) /* string 19 */
1802 || !pack_str(&msg
.ldapbase
) /* string 20 */
1803 || !pack_str(&msg
.crluri
) /* string 21 */
1804 || !pack_str(&msg
.crluri2
) /* string 22 */
1805 || !pack_str(&msg
.ocspuri
) /* string 23 */
1806 || !pack_str(&msg
.ike
) /* string 24 */
1807 || !pack_str(&msg
.esp
) /* string 25 */
1808 || !pack_str(&msg
.sc_data
) /* string 26 */
1809 || !pack_str(&msg
.whack_lease_ip
) /* string 27 */
1810 || !pack_str(&msg
.whack_lease_id
) /* string 28 */
1811 || !pack_str(&msg
.xauth_identity
) /* string 29 */
1812 || str_roof
- next_str
< (ptrdiff_t)msg
.keyval
.len
)
1813 diag("too many bytes of strings to fit in message to pluto");
1815 memcpy(next_str
, msg
.keyval
.ptr
, msg
.keyval
.len
);
1816 msg
.keyval
.ptr
= NULL
;
1817 next_str
+= msg
.keyval
.len
;
1819 msg
.magic
= ((opts_seen
& ~LELEM(OPT_SHUTDOWN
))
1820 | sc_seen
| lst_seen
| cd_seen
| ca_seen
) != LEMPTY
1821 || msg
.whack_options
1822 ? WHACK_MAGIC
: WHACK_BASIC_MAGIC
;
1824 /* send message to Pluto */
1825 if (access(ctl_addr
.sun_path
, R_OK
| W_OK
) < 0)
1832 fprintf(stderr
, "whack: no right to communicate with pluto (access(\"%s\"))\n"
1833 , ctl_addr
.sun_path
);
1836 fprintf(stderr
, "whack: Pluto is not running (no \"%s\")\n"
1837 , ctl_addr
.sun_path
);
1840 fprintf(stderr
, "whack: access(\"%s\") failed with %d %s\n"
1841 , ctl_addr
.sun_path
, errno
, strerror(e
));
1844 whack_exit(RC_WHACK_PROBLEM
);
1848 int sock
= socket(AF_UNIX
, SOCK_STREAM
, 0);
1849 int exit_status
= 0;
1850 ssize_t len
= next_str
- (char *)&msg
;
1856 fprintf(stderr
, "whack: socket() failed (%d %s)\n", e
, strerror(e
));
1857 whack_exit(RC_WHACK_PROBLEM
);
1860 if (connect(sock
, (struct sockaddr
*)&ctl_addr
1861 , offsetof(struct sockaddr_un
, sun_path
) + strlen(ctl_addr
.sun_path
)) < 0)
1865 fprintf(stderr
, "whack:%s connect() for \"%s\" failed (%d %s)\n"
1866 , e
== ECONNREFUSED?
" is Pluto running? " : ""
1867 , ctl_addr
.sun_path
, e
, strerror(e
));
1868 whack_exit(RC_WHACK_PROBLEM
);
1871 if (write(sock
, &msg
, len
) != len
)
1875 fprintf(stderr
, "whack: write() failed (%d %s)\n", e
, strerror(e
));
1876 whack_exit(RC_WHACK_PROBLEM
);
1879 /* for now, just copy reply back to stdout */
1882 char buf
[4097]; /* arbitrary limit on log line length */
1888 ssize_t rl
= read(sock
, be
, (buf
+ sizeof(buf
)-1) - be
);
1894 fprintf(stderr
, "whack: read() failed (%d %s)\n", e
, strerror(e
));
1895 whack_exit(RC_WHACK_PROBLEM
);
1900 fprintf(stderr
, "whack: last line from pluto too long or unterminated\n");
1909 char *le
= strchr(ls
, '\n');
1913 /* move last, partial line to start of buffer */
1914 memmove(buf
, ls
, be
-ls
);
1919 le
++; /* include NL in line */
1920 ignore_result(write(1, ls
, le
- ls
));
1922 /* figure out prefix number
1923 * and how it should affect our exit status
1926 unsigned long s
= strtoul(ls
, NULL
, 10);
1938 case RC_ENTERSECRET
:
1941 /* case RC_LOG_SERIOUS: */
1952 whack_exit(exit_status
);
1954 return -1; /* should never be reached */