📄 vty.c
字号:
/* * Virtual terminal [aka TeletYpe] interface routine. * Copyright (C) 1997, 98 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */#include <zebra.h>#include "linklist.h"#include "buffer.h"#include "version.h"#include "command.h"#include "sockunion.h"#include "thread.h"#include "memory.h"#include "str.h"#include "log.h"#include "prefix.h"#include "filter.h"/* Vty events */enum event { VTY_SERV, VTY_READ, VTY_WRITE, VTY_TIMEOUT_RESET,#ifdef VTYSH VTYSH_SERV, VTYSH_READ#endif /* VTYSH */ };static void vty_event (enum event, int, struct vty *);/* Extern host structure from command.c */extern struct host host;/* Vector which store each vty structure. */static vector vtyvec;/* Vty timeout value. */static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;/* Vty access-class command */static char *vty_accesslist_name = NULL;/* Vty access-calss for IPv6. */static char *vty_ipv6_accesslist_name = NULL;/* VTY server thread. */vector Vvty_serv_thread;/* Current directory. */char *vty_cwd = NULL;/* Configure lock. */static int vty_config;/* Login password check. */static int no_password_check = 0;/* Integrated configuration file path */char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;/* VTY standard output function. */intvty_out (struct vty *vty, const char *format, ...){ va_list args; int len = 0; int size = 1024; char buf[1024]; char *p = NULL; va_start (args, format); if (vty_shell (vty)) vprintf (format, args); else { /* Try to write to initial buffer. */ len = vsnprintf (buf, sizeof buf, format, args); /* Initial buffer is not enough. */ if (len < 0 || len >= size) { while (1) { if (len > -1) size = len + 1; else size = size * 2; p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size); if (! p) return -1; len = vsnprintf (p, size, format, args); if (len > -1 && len < size) break; } } /* When initial buffer is enough to store all output. */ if (! p) p = buf; /* Pointer p must point out buffer. */ if (vty_shell_serv (vty)) write (vty->fd, (u_char *) p, len); else buffer_write (vty->obuf, (u_char *) p, len); /* If p is not different with buf, it is allocated buffer. */ if (p != buf) XFREE (MTYPE_VTY_OUT_BUF, p); } va_end (args); return len;}#define TIME_BUF 27/* current time string. */inttime_str (char *buf){ time_t clock; struct tm *tm; int ret; time (&clock); tm = localtime (&clock); ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm); return ret;}intvty_log_out (struct vty *vty, const char *proto_str, const char *format, va_list va){ int len; int ret; char buf[1024]; char time_buf[TIME_BUF]; ret = time_str (time_buf); if (ret != 0) { snprintf (buf, sizeof buf, "%s ", time_buf); write (vty->fd, buf, strlen (time_buf) + 1); } snprintf (buf, sizeof buf, "%s: ", proto_str); write (vty->fd, buf, strlen (proto_str) + 2); len = vsnprintf (buf, sizeof buf, format, va); if (len < 0) return -1; write (vty->fd, (u_char *)buf, len); snprintf (buf, sizeof buf, "\r\n"); write (vty->fd, buf, 2); return len;}/* Output current time to the vty. */voidvty_time_print (struct vty *vty, int cr){ int ret; char buf [TIME_BUF]; ret = time_str (buf); if (ret == 0) { zlog (NULL, LOG_INFO, "strftime error"); return; } if (cr) vty_out (vty, "%s\n", buf); else vty_out (vty, "%s ", buf); return;}/* Say hello to vty interface. */voidvty_hello (struct vty *vty){ if (host.motd) vty_out (vty, host.motd);}/* Put out prompt and wait input from user. */static voidvty_prompt (struct vty *vty){ struct utsname names; const char*hostname; if (vty->type == VTY_TERM) { hostname = host.name; if (!hostname) { uname (&names); hostname = names.nodename; } vty_out (vty, cmd_prompt (vty->node), hostname); }}/* Send WILL TELOPT_ECHO to remote server. */voidvty_will_echo (struct vty *vty){ char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' }; vty_out (vty, "%s", cmd);}/* Make suppress Go-Ahead telnet option. */static voidvty_will_suppress_go_ahead (struct vty *vty){ char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' }; vty_out (vty, "%s", cmd);}/* Make don't use linemode over telnet. */static voidvty_dont_linemode (struct vty *vty){ char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' }; vty_out (vty, "%s", cmd);}/* Use window size. */static voidvty_do_window_size (struct vty *vty){ char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' }; vty_out (vty, "%s", cmd);}#if 0 /* Currently not used. *//* Make don't use lflow vty interface. */static voidvty_dont_lflow_ahead (struct vty *vty){ char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' }; vty_out (vty, "%s", cmd);}#endif /* 0 *//* Allocate new vty struct. */struct vty *vty_new (){ struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty)); new->obuf = (struct buffer *) buffer_new (100); new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ); new->max = VTY_BUFSIZ; new->sb_buffer = NULL; return new;}/* Authentication of vty */static voidvty_auth (struct vty *vty, char *buf){ char *passwd = NULL; enum node_type next_node = 0; int fail; char *crypt (const char *, const char *); switch (vty->node) { case AUTH_NODE: if (host.encrypt) passwd = host.password_encrypt; else passwd = host.password; if (host.advanced) next_node = host.enable ? VIEW_NODE : ENABLE_NODE; else next_node = VIEW_NODE; break; case AUTH_ENABLE_NODE: if (host.encrypt) passwd = host.enable_encrypt; else passwd = host.enable; next_node = ENABLE_NODE; break; } if (passwd) { if (host.encrypt) fail = strcmp (crypt(buf, passwd), passwd); else fail = strcmp (buf, passwd); } else fail = 1; if (! fail) { vty->fail = 0; vty->node = next_node; /* Success ! */ } else { vty->fail++; if (vty->fail >= 3) { if (vty->node == AUTH_NODE) { vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE); vty->status = VTY_CLOSE; } else { /* AUTH_ENABLE_NODE */ vty->fail = 0; vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE); vty->node = VIEW_NODE; } } }}/* Command execution over the vty interface. */intvty_command (struct vty *vty, char *buf){ int ret; vector vline; /* Split readline string up into the vector */ vline = cmd_make_strvec (buf); if (vline == NULL) return CMD_SUCCESS; ret = cmd_execute_command (vline, vty, NULL); if (ret != CMD_SUCCESS) switch (ret) { case CMD_WARNING: if (vty->type == VTY_FILE) vty_out (vty, "Warning...%s", VTY_NEWLINE); break; case CMD_ERR_AMBIGUOUS: vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); break; case CMD_ERR_NO_MATCH: vty_out (vty, "%% Unknown command.%s", VTY_NEWLINE); break; case CMD_ERR_INCOMPLETE: vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE); break; } cmd_free_strvec (vline); return ret;}char telnet_backward_char = 0x08;char telnet_space_char = ' ';/* Basic function to write buffer to vty. */static voidvty_write (struct vty *vty, char *buf, size_t nbytes){ if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) return; /* Should we do buffering here ? And make vty_flush (vty) ? */ buffer_write (vty->obuf, (u_char *)buf, nbytes);}/* Ensure length of input buffer. Is buffer is short, double it. */static voidvty_ensure (struct vty *vty, int length){ if (vty->max <= length) { vty->max *= 2; vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max); }}/* Basic function to insert character into vty. */static voidvty_self_insert (struct vty *vty, char c){ int i; int length; vty_ensure (vty, vty->length + 1); length = vty->length - vty->cp; memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length); vty->buf[vty->cp] = c; vty_write (vty, &vty->buf[vty->cp], length + 1); for (i = 0; i < length; i++) vty_write (vty, &telnet_backward_char, 1); vty->cp++; vty->length++;}/* Self insert character 'c' in overwrite mode. */static voidvty_self_insert_overwrite (struct vty *vty, char c){ vty_ensure (vty, vty->length + 1); vty->buf[vty->cp++] = c; if (vty->cp > vty->length) vty->length++; if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) return; vty_write (vty, &c, 1);}/* Insert a word into vty interface with overwrite mode. */static voidvty_insert_word_overwrite (struct vty *vty, char *str){ int len = strlen (str); vty_write (vty, str, len); strcpy (&vty->buf[vty->cp], str); vty->cp += len; vty->length = vty->cp;}/* Forward character. */static voidvty_forward_char (struct vty *vty){ if (vty->cp < vty->length) { vty_write (vty, &vty->buf[vty->cp], 1); vty->cp++; }}/* Backward character. */static voidvty_backward_char (struct vty *vty){ if (vty->cp > 0) { vty->cp--; vty_write (vty, &telnet_backward_char, 1); }}/* Move to the beginning of the line. */static voidvty_beginning_of_line (struct vty *vty){ while (vty->cp) vty_backward_char (vty);}/* Move to the end of the line. */static voidvty_end_of_line (struct vty *vty){ while (vty->cp < vty->length) vty_forward_char (vty);}static void vty_kill_line_from_beginning (struct vty *);static void vty_redraw_line (struct vty *);/* Print command line history. This function is called from vty_next_line and vty_previous_line. */static voidvty_history_print (struct vty *vty){ int length; vty_kill_line_from_beginning (vty); /* Get previous line from history buffer */ length = strlen (vty->hist[vty->hp]); memcpy (vty->buf, vty->hist[vty->hp], length); vty->cp = vty->length = length; /* Redraw current line */ vty_redraw_line (vty);}/* Show next command line history. */voidvty_next_line (struct vty *vty){ int try_index; if (vty->hp == vty->hindex) return; /* Try is there history exist or not. */ try_index = vty->hp; if (try_index == (VTY_MAXHIST - 1)) try_index = 0; else try_index++; /* If there is not history return. */ if (vty->hist[try_index] == NULL) return; else vty->hp = try_index; vty_history_print (vty);}/* Show previous command line history. */voidvty_previous_line (struct vty *vty){ int try_index; try_index = vty->hp; if (try_index == 0) try_index = VTY_MAXHIST - 1; else try_index--; if (vty->hist[try_index] == NULL) return; else vty->hp = try_index; vty_history_print (vty);}/* This function redraw all of the command line character. */static voidvty_redraw_line (struct vty *vty){ vty_write (vty, vty->buf, vty->length); vty->cp = vty->length;}/* Forward word. */static voidvty_forward_word (struct vty *vty){ while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') vty_forward_char (vty); while (vty->cp != vty->length && vty->buf[vty->cp] == ' ') vty_forward_char (vty);}/* Backward word without skipping training space. */static voidvty_backward_pure_word (struct vty *vty){ while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') vty_backward_char (vty);}/* Backward word. */static voidvty_backward_word (struct vty *vty){ while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') vty_backward_char (vty); while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') vty_backward_char (vty);}/* When '^D' is typed at the beginning of the line we move to the down level. */static voidvty_down_level (struct vty *vty){ vty_out (vty, "%s", VTY_NEWLINE); config_exit (NULL, vty, 0, NULL); vty_prompt (vty); vty->cp = 0;}/* When '^Z' is received from vty, move down to the enable mode. */voidvty_end_config (struct vty *vty){ vty_out (vty, "%s", VTY_NEWLINE); switch (vty->node) { case VIEW_NODE: case ENABLE_NODE: /* Nothing to do. */ break; case CONFIG_NODE: case INTERFACE_NODE: case ZEBRA_NODE: case RIP_NODE: case RIPNG_NODE: case BGP_NODE: case BGP_VPNV4_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: case BGP_IPV6_NODE: case RMAP_NODE: case OSPF_NODE: case OSPF6_NODE: case KEYCHAIN_NODE: case KEYCHAIN_KEY_NODE: case MASC_NODE: case VTY_NODE: vty_config_unlock (vty); vty->node = ENABLE_NODE; break; default: /* Unknown node, we have to ignore it. */ break; } vty_prompt (vty); vty->cp = 0;}/* Delete a charcter at the current point. */static voidvty_delete_char (struct vty *vty){ int i; int size; if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) return; if (vty->length == 0) { vty_down_level (vty); return; } if (vty->cp == vty->length) return; /* completion need here? */ size = vty->length - vty->cp; vty->length--; memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1); vty->buf[vty->length] = '\0'; vty_write (vty, &vty->buf[vty->cp], size - 1); vty_write (vty, &telnet_space_char, 1); for (i = 0; i < size; i++) vty_write (vty, &telnet_backward_char, 1);}/* Delete a character before the point. */static voidvty_delete_backward_char (struct vty *vty){ if (vty->cp == 0) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -