├── CHANGELOG ├── INSTALL ├── README ├── cisco_color.h ├── cisco_color_ssh.patch └── cisco_color.c /CHANGELOG: -------------------------------------------------------------------------------- 1 | V1.1 2 | - Added rules for juniper's hostname, and the "show configuration" and "show configuration | compare" commands 3 | - Moved cisco_color.c and cisco_color.h out of the patch file 4 | 5 | V1.0 - Initial release 6 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | To build: 2 | 3 | 1. Download and extract the OpenSSH Source version 5.9p1 from one of the mirrors listed at http://www.openssh.com/portable.html 4 | 5 | wget http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-5.9p1.tar.gz 6 | 7 | 2. Apply the patch file to the source of openssh 8 | 9 | patch -i cisco_color_ssh.patch 10 | 11 | 3. Copy the two new files to the directory with the openssh source 12 | 13 | cisco_color.c 14 | cisco_color.h 15 | 16 | 4. Compile the ssh client 17 | 18 | ./configure 19 | make ssh 20 | 21 | OSX users might need to use "./configure --without-openssl-header-check" 22 | 23 | !!!!!!!!!!!!!!!!!! 24 | Please do NOT use "make install" as it will likely overwrite or at least conflict 25 | with the version of SSH already installed. 26 | !!!!!!!!!!!!!!!!!! 27 | 28 | What I did to install was: 29 | 30 | sudo cp ./ssh /usr/local/bin/cssh 31 | 32 | This copies the client and renames it so it doesn't conflict. 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This modification to OpenSSH 5.9p1 adds some color to Cisco CLI. 2 | 3 | I don't know about you, but I spend way too much time in Cisco's CLI. I looked around 4 | for a way to add color to Cisco's outputs, but was unable to find anything. 5 | 6 | I finally came up with a patch for OpenSSH's ssh client (the "ssh" command in *nix/BSD/OSX/etc) 7 | 8 | The patch causes ssh to filter all incoming data and when it matches certain 9 | rules (defined with regex) apply color. 10 | 11 | So far I haven't created many "rules". If someone wants to help me do so that would 12 | be awesome! Right now it highlights the hostname/config prompts, interface status 13 | (up/down/admin down), some interface config commands, and some other stuff. There's 14 | potential to do so much though :) 15 | 16 | The rules are specified in cisco_color.c. If you make any changes you need to recompile. 17 | 18 | While I've been using the ssh client for a while with cisco devices without issues, I obviously take no responsibility for any issues you encounter! 19 | 20 | Limitations/Known Issues: 21 | - Matching is done per packet. If the data to be matched spans more then one packet 22 | then it won't match. This is most noticable if you ssh to a serial console server, as 23 | the serial output is slow enough to cause SSH to send a packet per character, so nothing 24 | ever matches 25 | 26 | - Do not use the modified versions of the other programs in this package (scp, etc) You 27 | will likely encounter corrupted data. 28 | 29 | 30 | - Thomas St.Pierre thomas@samoht.ca 31 | -------------------------------------------------------------------------------- /cisco_color.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Thomas St.Pierre. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 1. Redistributions of source code must retain the above copyright notice, this list of 7 | conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 10 | of conditions and the following disclaimer in the documentation and/or other materials 11 | provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY Thomas St.Pierre ''AS IS'' AND ANY EXPRESS OR IMPLIED 14 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 15 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Thomas St.Pierre OR 16 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 17 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 18 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 19 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 21 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | 23 | The views and conclusions contained in the software and documentation are those of the 24 | authors and should not be interpreted as representing official policies, either expressedor implied, of Thomas St.Pierre. 25 | */ 26 | 27 | 28 | 29 | #define MAXMATCH 20 30 | #define BRIGHT_GREEN "\033[1m" 31 | 32 | #include 33 | 34 | struct color_match{ 35 | const char *pattern; 36 | const char *insert_before[MAXMATCH]; 37 | regex_t compiled; 38 | }; 39 | 40 | int init_patterns(); 41 | 42 | int process_patterns(char *data, int data_len); 43 | 44 | 45 | -------------------------------------------------------------------------------- /cisco_color_ssh.patch: -------------------------------------------------------------------------------- 1 | diff -Naur ../openssh-5.9p1/Makefile.in ./Makefile.in 2 | --- ../openssh-5.9p1/Makefile.in 2011-08-05 16:15:18.000000000 -0400 3 | +++ ./Makefile.in 2011-11-29 08:58:27.000000000 -0500 4 | @@ -75,7 +75,7 @@ 5 | 6 | SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ 7 | sshconnect.o sshconnect1.o sshconnect2.o mux.o \ 8 | - roaming_common.o roaming_client.o 9 | + roaming_common.o roaming_client.o cisco_color.o 10 | 11 | SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ 12 | audit.o audit-bsm.o audit-linux.o platform.o \ 13 | @@ -231,7 +231,9 @@ 14 | $(AUTORECONF) 15 | -rm -rf autom4te.cache 16 | 17 | -install: $(CONFIGFILES) $(MANPAGES) $(TARGETS) install-files install-sysconf host-key check-config 18 | +install: 19 | + echo "Please install the ssh binary manually to ensure you don't overwrite system" 20 | + echo "default." 21 | install-nokeys: $(CONFIGFILES) $(MANPAGES) $(TARGETS) install-files install-sysconf 22 | install-nosysconf: $(CONFIGFILES) $(MANPAGES) $(TARGETS) install-files 23 | 24 | diff -Naur ../openssh-5.9p1/channels.c ./channels.c 25 | --- ../openssh-5.9p1/channels.c 2011-06-22 18:31:57.000000000 -0400 26 | +++ ./channels.c 2011-11-29 08:50:16.000000000 -0500 27 | @@ -77,6 +77,8 @@ 28 | #include "key.h" 29 | #include "authfd.h" 30 | #include "pathnames.h" 31 | +#include "cisco_color.h" 32 | + 33 | 34 | /* -- channel core */ 35 | 36 | @@ -2263,6 +2265,7 @@ 37 | int id; 38 | char *data; 39 | u_int data_len, win_len; 40 | + int increased; 41 | Channel *c; 42 | 43 | /* Get the channel number and verify it. */ 44 | @@ -2282,6 +2285,8 @@ 45 | if (c->datagram) 46 | win_len += 4; /* string length header */ 47 | 48 | + /* Parse our regexes */ 49 | + increased = process_patterns(data,data_len); 50 | /* 51 | * Ignore data for protocol > 1.3 if output end is no longer open. 52 | * For protocol 2 the sending side is reducing its window as it sends 53 | @@ -2310,9 +2315,9 @@ 54 | c->local_window -= win_len; 55 | } 56 | if (c->datagram) 57 | - buffer_put_string(&c->output, data, data_len); 58 | + buffer_put_string(&c->output, data, data_len + increased); 59 | else 60 | - buffer_append(&c->output, data, data_len); 61 | + buffer_append(&c->output, data, data_len + increased); 62 | packet_check_eom(); 63 | } 64 | 65 | diff -Naur ../openssh-5.9p1/ssh.c ./ssh.c 66 | --- ../openssh-5.9p1/ssh.c 2011-08-05 16:18:16.000000000 -0400 67 | +++ ./ssh.c 2011-11-29 08:50:23.000000000 -0500 68 | @@ -104,6 +104,7 @@ 69 | #include "uidswap.h" 70 | #include "roaming.h" 71 | #include "version.h" 72 | +#include "cisco_color.h" 73 | 74 | #ifdef ENABLE_PKCS11 75 | #include "ssh-pkcs11.h" 76 | @@ -249,6 +250,9 @@ 77 | struct servent *sp; 78 | Forward fwd; 79 | 80 | + /* compile Regex for color matching */ 81 | + init_patterns(); 82 | + 83 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 84 | sanitise_stdfd(); 85 | 86 | -------------------------------------------------------------------------------- /cisco_color.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Thomas St.Pierre. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Thomas St.Pierre ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Thomas St.Pierre OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Thomas St.Pierre. 27 | */ 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #define MAXMATCH 20 34 | 35 | /* Terminal Color codes */ 36 | #define TERM_BRIGHT_GREEN "\033[1m" 37 | #define TERM_GREEN "\033[1;32m" 38 | #define TERM_BOLD_RED "\033[1;31m" 39 | #define TERM_RED "\033[31m" 40 | #define TERM_PURPLE "\033[35m" 41 | #define TERM_BOLD_PURPLE "\033[1;35m" 42 | #define TERM_BRIGHT_YELLOW "\033[1;33m" 43 | #define TERM_YELLOW "\033[33m" 44 | #define TERM_WHITE "\033[37m" 45 | #define TERM_BLUE "\033[34m" 46 | #define TERM_LIGHT_BLUE "\033[1;34m" 47 | #define TERM_CYAN "\033[36m" 48 | 49 | #define TERM_BG_GREEN "\033[42m" 50 | #define TERM_WARNING "\033[41m\033[1m" 51 | 52 | #define TERM_NONE "\033[0m" 53 | 54 | /* 55 | Define our rules! 56 | Rules Are defined as a struct, first variable is a regex. The entire line is used to match 57 | context of what you want to color. Within the regex you use sub-expressions to define 58 | what to color. For example with the regex "This is (some) context", it will match the 59 | entire line, but only the word 'some' will be colored. Second variable is an array which 60 | contains strings that will be inserted right before every matched sub-expression. (usually 61 | terminal escapes codes, but could be any string) 62 | 63 | Last variable is used internally to store compiled regex's 64 | */ 65 | 66 | struct color_match{ 67 | const char *pattern; 68 | const char *insert_before[MAXMATCH]; 69 | regex_t compiled; 70 | } patterns [] = { 71 | /* Logs */ 72 | {"^\\*?([A-Z][a-z]{2}[ 0-9]{3}[0-9 ]{0,5} [0-9]{1,2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3} [A-Z]{3}): (%[A-Z0-9_-]+:) (.*)$", {TERM_CYAN, TERM_RED, TERM_BLUE}}, 73 | 74 | /* Interface Name */ 75 | {"^(interface) ([a-zA-Z-]+)([0-9./]+)",{TERM_YELLOW, TERM_CYAN, TERM_BOLD_PURPLE}}, 76 | 77 | /* Interface parameters */ 78 | {"^ (description) (.*)$", {TERM_YELLOW, TERM_BLUE}}, 79 | {"^ (ip address) ([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}) ([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}) (secondary)", 80 | {TERM_YELLOW, TERM_PURPLE, TERM_PURPLE, TERM_BRIGHT_GREEN}}, 81 | {"^ (ip address) ([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}) ([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}).$", 82 | {TERM_YELLOW, TERM_PURPLE, TERM_PURPLE}}, 83 | {"^ (ip vrf forwarding) ([a-zA-Z0-9_-]+).$", {TERM_YELLOW,TERM_RED}}, 84 | {"^ (ip nat) (inside|outside).$", {TERM_YELLOW,TERM_RED}}, 85 | {"^ (encapsulation dot1Q) ([0-9]{1,4}).$", {TERM_YELLOW, TERM_PURPLE }}, 86 | {"^ (shutdown).$", {TERM_RED}}, 87 | 88 | /* Interface Status */ 89 | {"is (up), line protocol is (down)", {TERM_BRIGHT_GREEN, TERM_BOLD_RED}}, 90 | {"is (down), line protocol is (down)", {TERM_BOLD_RED, TERM_BOLD_RED}}, 91 | {"is (up), line protocol is (up)", {TERM_BRIGHT_GREEN, TERM_BRIGHT_GREEN}}, 92 | {"is (administratively down), line protocol is (down)", {TERM_YELLOW, TERM_YELLOW}}, 93 | {"is ([a-z]+), line protocol is ([a-z]+)", {TERM_WARNING, TERM_WARNING}}, 94 | 95 | /* Interface speeds */ 96 | {"^ [0-9]{1,2} [a-z]{6} [a-z]{5,6} rate ([0-9]{1,3})([0-9]{3})([0-9]{3})([0-9]{3}) bits.*$", {TERM_PURPLE, TERM_CYAN, TERM_BLUE, TERM_CYAN}}, 97 | {"^ [0-9]{1,2} [a-z]{6} [a-z]{5,6} rate ([0-9]{1,3})([0-9]{3})([0-9]{3}) bits.*$", {TERM_CYAN, TERM_BLUE, TERM_CYAN}}, 98 | {"^ [0-9]{1,2} [a-z]{6} [a-z]{5,6} rate ([0-9]{1,3})([0-9]{3}) bits.*$", {TERM_BLUE, TERM_CYAN}}, 99 | {"^ [0-9]{1,2} [a-z]{6} [a-z]{5,6} rate ([0-9]{1,3}) bits.*$", {TERM_CYAN}}, 100 | 101 | 102 | 103 | /* Hostname / config prompts */ 104 | {"^([a-zA-Z0-9\\._\\-]*)(\\(config)(-[a-z_-]+)(\\))#",{TERM_BRIGHT_GREEN,TERM_RED,TERM_PURPLE,TERM_RED}}, 105 | {"^([a-zA-Z0-9\\._\\-]*)(\\(config\\))#",{TERM_BRIGHT_GREEN,TERM_RED}}, 106 | {"^([a-zA-Z0-9\\._-]*)#",{TERM_BRIGHT_GREEN}}, 107 | {"^([a-zA-Z0-9\\._-]*)>",{TERM_BRIGHT_GREEN}}, 108 | 109 | /* OSPF config */ 110 | {"^(router ospf) ([0-9]+) (vrf) ([a-zA-Z_-]+).$", {TERM_YELLOW, TERM_PURPLE, TERM_YELLOW, TERM_RED}}, 111 | {"^(router ospf) ([0-9]+).$", {TERM_YELLOW, TERM_PURPLE}}, 112 | {"^( log-adjacency-changes).$", {TERM_YELLOW}}, 113 | {"^ (redistribute) ([a-zA-Z0-9 ]+) (subnets).$", {TERM_YELLOW, TERM_PURPLE, TERM_YELLOW}}, 114 | {"^ (network) ([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3} [0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}) (area) ([0-9]+).$", 115 | {TERM_YELLOW, TERM_PURPLE, TERM_YELLOW, TERM_RED}}, 116 | {"^ (default-information) (originate)(.*)$", { TERM_YELLOW, TERM_RED, TERM_PURPLE}}, 117 | 118 | /* Cisco "show route-map" */ 119 | {"^route-map (.+), (permit), sequence ([0-9]+)", {TERM_YELLOW, TERM_GREEN, TERM_PURPLE}}, 120 | {"^route-map (.+), (deny), sequence ([0-9]+)", {TERM_YELLOW, TERM_RED, TERM_PURPLE}}, 121 | {"^route-map (.+) (permit) ([0-9]+)", {TERM_YELLOW, TERM_GREEN, TERM_PURPLE}}, 122 | {"^route-map (.+) (deny) ([0-9]+)", {TERM_YELLOW, TERM_RED, TERM_PURPLE}}, 123 | 124 | 125 | 126 | /* BGP Config */ 127 | {"^(router bgp) ([0-9]+).$", {TERM_YELLOW, TERM_PURPLE}}, 128 | {"^ (address-family) ([a-z0-9]+) (vrf) ([a-zA-Z0-9_-]+).$", {TERM_YELLOW, TERM_PURPLE, TERM_YELLOW, TERM_RED}}, 129 | {"^ (address-family) ([a-z0-9]+).$", {TERM_YELLOW, TERM_PURPLE}}, 130 | {"^ {1,2}(no) (synchronization).$", {TERM_RED, TERM_YELLOW}}, 131 | {"^ {1,2}(neighbor) ([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}) (remote-as) ([0-9]+).$", 132 | {TERM_YELLOW, TERM_PURPLE, TERM_YELLOW, TERM_RED}}, 133 | {"^ {1,2}(neighbor) ([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}) (description) ([a-zA-Z0-9 _-]+).$", 134 | {TERM_YELLOW, TERM_PURPLE, TERM_YELLOW, TERM_BLUE}}, 135 | 136 | 137 | 138 | /* Routing */ 139 | {"^(Routing entry for )([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})/([0-9]{2}).$", {TERM_YELLOW,TERM_PURPLE,TERM_RED}}, 140 | {"^ Known via \"([a-z0-9 ]+)\"", {TERM_CYAN}}, 141 | 142 | {"^(ip route vrf) ([a-zA-Z0-9_-]*) ([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3} [0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})(.*)$", 143 | {TERM_YELLOW, TERM_RED, TERM_PURPLE, TERM_BRIGHT_GREEN}}, 144 | {"^(ip route) ([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3} [0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})(.*)$", 145 | {TERM_YELLOW, TERM_PURPLE, TERM_BRIGHT_GREEN}}, 146 | 147 | /* Juniper Hostname */ 148 | {"^(\\{[a-zA-Z0-9_:-]{1,30}\\}).$", {TERM_CYAN}}, 149 | {"^(\\{[a-zA-Z0-9_:-]{1,30}\\})(\\[[a-zA-Z0-9_ -]*\\])", {TERM_CYAN, TERM_PURPLE}}, 150 | {"^(\\[[a-zA-Z0-9_ -/]*\\]).$", {TERM_PURPLE}}, 151 | {"^([a-zA-Z0-9_-]{1,30})@([a-zA-Z0-9\\._-]{1,30})[#>]",{TERM_YELLOW, TERM_BRIGHT_GREEN}}, 152 | 153 | /* Juniper show | compare */ 154 | {"^\\+ (.*)$", {TERM_GREEN}}, 155 | {"^\\- (.*)$", {TERM_RED}}, 156 | 157 | /* Juniper config */ 158 | {"^[ ]*([-a-zA-Z0-9_/]+) ([^ ]+) (\\{).$", {TERM_BRIGHT_YELLOW, TERM_PURPLE, TERM_RED}}, 159 | {"^[ ]*([a-zA-Z0-9_ -/]+) (\\{).$", {TERM_BRIGHT_YELLOW, TERM_RED}}, 160 | {"^[ ]*(}).$", {TERM_RED}}, 161 | {"^[ ]*([a-zA-Z0-9/\\._-]+ )([^ ]+);.$", {TERM_LIGHT_BLUE, TERM_CYAN}}, 162 | {"^[ ]*([a-zA-Z0-9/\\._-]+);.$", {TERM_CYAN}}, 163 | {"^[ ]*([a-zA-Z0-9/\\._-]+) (\\[) (.+) (\\]);.$", {TERM_LIGHT_BLUE, TERM_YELLOW, TERM_CYAN, TERM_YELLOW}}, 164 | 165 | 166 | /* IP Addresses */ 167 | 168 | {"([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})(\\.[0-9]{1,3})(/[0-9]{1,2})", {TERM_WHITE, TERM_WHITE, TERM_RED}}, 169 | {"([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})(\\.[0-9]{1,3})", {TERM_WHITE, TERM_WHITE}}, 170 | 171 | /* Big numbers */ 172 | {" ([0-9]{1,3})([0-9]{3})([0-9]{3})([0-9]{3}) ", {TERM_PURPLE, TERM_CYAN, TERM_BLUE, TERM_CYAN}}, 173 | {" ([0-9]{1,3})([0-9]{3})([0-9]{3}) ", {TERM_CYAN, TERM_BLUE, TERM_CYAN}} 174 | 175 | }; 176 | 177 | /* This function loops through each regex and compiles it so it's ready to use */ 178 | int init_patterns() 179 | { 180 | 181 | 182 | 183 | unsigned int i; 184 | /* compile regexs */ 185 | 186 | for (i = 0; i < sizeof(patterns)/sizeof(patterns[0]); i++) 187 | { 188 | if (regcomp(&patterns[i].compiled, patterns[i].pattern, REG_EXTENDED|REG_NEWLINE)) 189 | { 190 | fprintf(stderr, "Error compiling pattern: %s\n", 191 | patterns[i].pattern); 192 | 193 | return 1; 194 | } 195 | } 196 | return 0; 197 | } 198 | 199 | 200 | /* This function is called for every incoming packet. It compares it to each regex and inserts 201 | codes as appropriate */ 202 | int process_patterns(char *data, int data_len) 203 | { 204 | unsigned int i; /* main for loop, keeps track of which rule/pattern we're on */ 205 | int c; /* Used in inner loop to keep track of which sub-expression we're at */ 206 | char buffer[32767]; /* Buffer, we rebuild strings with color codes here */ 207 | char mydata[32767]; /* Keeps track of the data between loops */ 208 | int increased; /* Keeps track of how much we lengthened data */ 209 | regmatch_t matches[MAXMATCH]; /* Used as results of regexec for what we matched */ 210 | regoff_t last_match; /* used to loop through the data incase we match the data more than once */ 211 | 212 | increased = 0; 213 | 214 | /* Copy the string to the correct length. Data refrences the whole SSH buffer (I think) and has garbage */ 215 | 216 | memset(mydata, '\0', sizeof(mydata)); 217 | strncat(mydata, data, data_len); 218 | 219 | /* execute regexs */ 220 | for (i = 0; i < sizeof(patterns)/sizeof(patterns[0]); i++) 221 | { 222 | last_match = 0; 223 | while (regexec(&patterns[i].compiled, mydata + last_match, MAXMATCH, matches, 0) == 0) 224 | { 225 | if ((int)matches[1].rm_eo > 0) 226 | { 227 | 228 | 229 | /* Reset variables */ 230 | memset(buffer, '\0', sizeof(buffer)); 231 | c = 1; 232 | 233 | /* Copy start of string */ 234 | strncat(buffer, mydata, (int)matches[c].rm_so + last_match); 235 | 236 | while (((int)matches[c].rm_so >= 0) && (c < MAXMATCH) ) 237 | { 238 | /* Insert before match */ 239 | strcat(buffer, patterns[i].insert_before[c-1]); 240 | 241 | /*copy what matched */ 242 | strncat(buffer, mydata + (int)matches[c].rm_so + last_match, 243 | (int)matches[c].rm_eo - (int)matches[c].rm_so); 244 | 245 | /* Insert the after match */ 246 | strcat(buffer, TERM_NONE); 247 | 248 | /* Are there any more matches for this pattern? */ 249 | if ( (c+1 > MAXMATCH) || ((int)matches[c+1].rm_so < 0 )) 250 | { 251 | /* Nope! Finish string! */ 252 | strncat(buffer, mydata + (int)matches[c].rm_eo + last_match, 253 | strlen(mydata) - (int)matches[c].rm_eo + last_match); 254 | } else 255 | { 256 | /* Copy up until next match */ 257 | strncat(buffer, mydata + (int)matches[c].rm_eo + last_match, 258 | (int)matches[c+1].rm_so - (int)matches[c].rm_eo); 259 | } 260 | 261 | /* Increase the data length by what we added */ 262 | increased += strlen(patterns[i].insert_before[c-1]) + strlen(TERM_NONE); 263 | c++; 264 | } 265 | /* Copy the buffer back to mydata */ 266 | strcpy(mydata, buffer); 267 | } 268 | 269 | last_match += (int)matches[0].rm_eo; 270 | } 271 | } 272 | 273 | /* Copy my data back to real data, and return increased length (used in channels.c) */ 274 | strcpy(data, mydata); 275 | return increased; 276 | } 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | --------------------------------------------------------------------------------