-
Notifications
You must be signed in to change notification settings - Fork 0
/
command-line-history-and-editing-for-ipsec-utilities.html
7 lines (7 loc) · 5.83 KB
/
command-line-history-and-editing-for-ipsec-utilities.html
1
2
3
4
5
6
7
<html><body>
<head>
<title>Command line history and editing for IPsec utilities | Oracle Czech techie's adventures Blog</title>
<meta name="publish_date" content="2009-03-31 05:19:36">
</head>
<p>Since the days when <a href="http://blogs.sun.com/jbeck/entry/adding_command_line_editing_history">John Beck added <br/>command line editing to <tt>zonecfg</tt></a><br/><a href="http://blogs.sun.com/mbp/entry/enhanced_command_line_editing_support">Mark Phalan did similar thing <br/>to Kerberos utilities</a> and Huie-Ying Lee to <tt>sftp</tt>. IPsec utilities (ipseckey(1M) and ikeadm(1M))<br/>offered the ability to enter commands in interactive mode for a long time but <br/>only since Nevada build 112, the commands support command line editing and history too. Again, thanks to <br/><a href="http://www.astro.caltech.edu/~mcs/tecla/">libtecla</a> (shipped with Solaris/OpenSolaris).</p><p>Lessons learned:</p><ul><li><i>adding full-blown command line editing support is hard.</i><br/><br/> Adding the initial support is quite easy. However, more advanced features could require substantial work. <br/> This is especially true for tab completion. For <tt>sftp</tt> Huie-Ying decided to add tab completion<br/> in the future phase because of the ambiguities when completing names of files (when to complete local <br/> files versus remote files).<br/><br/> I did the same with tab completion for IPsec utilities - the integration only delivers basic command line<br/> editing support, without tab completion. The problem with ipseckey(1M) and ikeadm(1M) is<br/> that their grammar is quite bifurcated and has contexts. For example, you cannot use <tt>encr_alg</tt><br/> with AH SAs in <tt>ipseckey</tt>. Or, it would be erroneous to tab complete a valid command in the middle<br/> of entering a key if the key hex sequence contained sub-string of a valid command. The hardest part is<br/> I think offering the right tables of valid commands in given context. E.g. in our case a command line in <br/> our case must start with top-level command. Each top-level command offers several valid sub-commands and<br/> we do not offer invalid sub-commands for given top-level command so there is a necessity to track<br/> the state of the finite state machine describing the grammar contexts.<br/><br/> Also, after the user entered <tt>src</tt> we do not want to allow him to enter it again on the same command line. <br/> Also, if the user already entered say <tt>add esp spi</tt> we are expecting SPI number, not a command name.<br/><br/> Ideally, to solve this problem in nice way there should be a meta library (or additional API in libtecla) <br/> which would offer the ability to link command tables and set the contexts.</li><li><i>interruptible cycles in command line mode</i><br/><tt>ipseckey</tt>'s <tt>monitor</tt> command reads from a <tt>PF_KEY</tt> socket in a loop. The loop<br/> is normally interruptible by SIGINT. To do so in libtecla environment (we do not want to exit the command line<br/> upon SIGINT and yet still need to interrupt the cycle), something like <a href="http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipseckey.c#domonitor">this</a> <br/> is needed:<pre> static void<br/> monitor_catch(int signal)<br/> {<br/> if (!interactive)<br/> errx(signal, gettext("Bailing on signal %d."), signal);<br/> }<br/> void<br/> doreadcycle(void)<br/> {<br/> ...<br/> /\* Catch \^C. \*/<br/> newsig.sa_handler = monitor_catch;<br/> newsig.sa_flags = 0;<br/> (void) sigemptyset(&newsig.sa_mask);<br/> (void) sigaddset(&newsig.sa_mask, SIGINT);<br/> (void) sigaction(SIGINT, &newsig, &oldsig);<br/> for (; ; ) {<br/> rc = read(keysock, samsg, sizeof (get_buffer));<br/> /\* handle the data \*/<br/> }<br/> /\* restore old behavior \*/<br/> if (interactive)<br/> (void) sigaction(SIGINT, &oldsig, NULL);<br/> }</pre></li><li><i>interaction with SMF</i><br/><br/> While it's fine to bail out in interactive mode with error, due to the nature of IPsec commands<br/> (they can read the config files using the same routines as for interactive mode and they are used as SMF services <br/> to bring up IPsec policy and keys after boot) we need to distinguish the interactive and non-interactive mode.</li><li><i>maximum command line history value</i><br/><br/> It seems that the second parameter to <tt>new_GetLine()</tt> - <tt>histlen</tt> is commonly misunderstood.<br/> This variable does not express the number of maximum lines in the history but instead maximum size of the history<br/> buffer <b>in bytes</b>. If the buffer becomes full, libtecla does not trim the last line but shifts instead.<br/><br/> Given the first parameter to <tt>new_GetLine()</tt> expresses maximum command line size (in bytes) one needs to<br/> do some calculations and estimates on what will be needed too avoid too big buffer - <tt>ipseckey</tt> is used to enter <br/> 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<br/> this will give us 1 megabyte buffer which seems too much for a simple application. Thus I did some guessing<br/> and set the buffer size accordingly:<br/><br/> For "common" ipseckey configuration commands (think moderately bifurcated 'add') it's cca 300 characters. <br/> Mostly however, the users enter query commands like 'flush esp', 'dump ah' and the like so this is somewhere around say <br/> 30 characters. Say 30% of the commands are configuration and the rest is queries. To hold 100 such commands only cca 10K <br/> memory is required. In the end I chose 64K to be able to hold 15 of the biggies (4K) commands. </li></ul>
</body></html>