Solaris serviceability and nifty tools

Command line history and editing for IPsec utilities

Since the days when John Beck added
command line editing to zonecfg

Mark Phalan did similar thing
to Kerberos utilities
and Huie-Ying Lee to sftp. IPsec utilities (ipseckey(1M) and ikeadm(1M))
offered the ability to enter commands in interactive mode for a long time but
only since Nevada build 112, the commands support command line editing and history too. Again, thanks to
libtecla (shipped with Solaris/OpenSolaris).

Lessons learned:

  • adding full-blown command line editing support is hard.

    Adding the initial support is quite easy. However, more advanced features could require substantial work.
    This is especially true for tab completion. For sftp Huie-Ying decided to add tab completion
    in the future phase because of the ambiguities when completing names of files (when to complete local
    files versus remote files).

    I did the same with tab completion for IPsec utilities - the integration only delivers basic command line
    editing support, without tab completion. The problem with ipseckey(1M) and ikeadm(1M) is
    that their grammar is quite bifurcated and has contexts. For example, you cannot use encr_alg
    with AH SAs in ipseckey. Or, it would be erroneous to tab complete a valid command in the middle
    of entering a key if the key hex sequence contained sub-string of a valid command. The hardest part is
    I think offering the right tables of valid commands in given context. E.g. in our case a command line in
    our case must start with top-level command. Each top-level command offers several valid sub-commands and
    we do not offer invalid sub-commands for given top-level command so there is a necessity to track
    the state of the finite state machine describing the grammar contexts.

    Also, after the user entered src we do not want to allow him to enter it again on the same command line.
    Also, if the user already entered say add esp spi we are expecting SPI number, not a command name.

    Ideally, to solve this problem in nice way there should be a meta library (or additional API in libtecla)
    which would offer the ability to link command tables and set the contexts.
  • interruptible cycles in command line mode
    ipseckey's monitor command reads from a PF_KEY socket in a loop. The loop
    is normally interruptible by SIGINT. To do so in libtecla environment (we do not want to exit the command line
    upon SIGINT and yet still need to interrupt the cycle), something like this
    is needed:
         static void
    monitor_catch(int signal)
    if (!interactive)
    errx(signal, gettext("Bailing on signal %d."), signal);
    /\* Catch \^C. \*/
    newsig.sa_handler = monitor_catch;
    newsig.sa_flags = 0;
    (void) sigemptyset(&newsig.sa_mask);
    (void) sigaddset(&newsig.sa_mask, SIGINT);
    (void) sigaction(SIGINT, &newsig, &oldsig);
    for (; ; ) {
    rc = read(keysock, samsg, sizeof (get_buffer));
    /\* handle the data \*/
    /\* restore old behavior \*/
    if (interactive)
    (void) sigaction(SIGINT, &oldsig, NULL);
  • interaction with SMF

    While it's fine to bail out in interactive mode with error, due to the nature of IPsec commands
    (they can read the config files using the same routines as for interactive mode and they are used as SMF services
    to bring up IPsec policy and keys after boot) we need to distinguish the interactive and non-interactive mode.
  • maximum command line history value

    It seems that the second parameter to new_GetLine() - histlen is commonly misunderstood.
    This variable does not express the number of maximum lines in the history but instead maximum size of the history
    buffer in bytes. If the buffer becomes full, libtecla does not trim the last line but shifts instead.

    Given the first parameter to new_GetLine() expresses maximum command line size (in bytes) one needs to
    do some calculations and estimates on what will be needed too avoid too big buffer - ipseckey is used to enter
    key material so the line could become quite long. Say we wanted to keep 1024 lines. If the maximum length of the line is 1024
    this will give us 1 megabyte buffer which seems too much for a simple application. Thus I did some guessing
    and set the buffer size accordingly:

    For "common" ipseckey configuration commands (think moderately bifurcated 'add') it's cca 300 characters.
    Mostly however, the users enter query commands like 'flush esp', 'dump ah' and the like so this is somewhere around say
    30 characters. Say 30% of the commands are configuration and the rest is queries. To hold 100 such commands only cca 10K
    memory is required. In the end I chose 64K to be able to hold 15 of the biggies (4K) commands.

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.