|
version 1.1.1.2, 2012/10/09 09:22:28
|
version 1.1.1.4, 2016/11/02 10:09:10
|
|
Line 38
|
Line 38
|
| #include "network.h" |
#include "network.h" |
| |
|
| #include <arpa/telnet.h> |
#include <arpa/telnet.h> |
| |
#include <termios.h> |
| |
|
| /* Vty events */ |
/* Vty events */ |
| enum event |
enum event |
|
Line 57 static void vty_event (enum event, int, struct vty *);
|
Line 58 static void vty_event (enum event, int, struct vty *);
|
| |
|
| /* Extern host structure from command.c */ |
/* Extern host structure from command.c */ |
| extern struct host host; |
extern struct host host; |
| |
| /* Vector which store each vty structure. */ |
/* Vector which store each vty structure. */ |
| static vector vtyvec; |
static vector vtyvec; |
| |
|
|
Line 71 static char *vty_accesslist_name = NULL;
|
Line 72 static char *vty_accesslist_name = NULL;
|
| static char *vty_ipv6_accesslist_name = NULL; |
static char *vty_ipv6_accesslist_name = NULL; |
| |
|
| /* VTY server thread. */ |
/* VTY server thread. */ |
| vector Vvty_serv_thread; | static vector Vvty_serv_thread; |
| |
|
| /* Current directory. */ |
/* Current directory. */ |
| char *vty_cwd = NULL; |
char *vty_cwd = NULL; |
|
Line 89 static u_char restricted_mode = 0;
|
Line 90 static u_char restricted_mode = 0;
|
| /* Integrated configuration file path */ |
/* Integrated configuration file path */ |
| char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; |
char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; |
| |
|
| |
| /* VTY standard output function. */ |
/* VTY standard output function. */ |
| int |
int |
| vty_out (struct vty *vty, const char *format, ...) |
vty_out (struct vty *vty, const char *format, ...) |
|
Line 110 vty_out (struct vty *vty, const char *format, ...)
|
Line 111 vty_out (struct vty *vty, const char *format, ...)
|
| { |
{ |
| /* Try to write to initial buffer. */ |
/* Try to write to initial buffer. */ |
| va_start (args, format); |
va_start (args, format); |
| len = vsnprintf (buf, sizeof buf, format, args); | len = vsnprintf (buf, sizeof(buf), format, args); |
| va_end (args); |
va_end (args); |
| |
|
| /* Initial buffer is not enough. */ |
/* Initial buffer is not enough. */ |
|
Line 184 vty_log_out (struct vty *vty, const char *level, const
|
Line 185 vty_log_out (struct vty *vty, const char *level, const
|
| buf[len++] = '\r'; |
buf[len++] = '\r'; |
| buf[len++] = '\n'; |
buf[len++] = '\n'; |
| |
|
| if (write(vty->fd, buf, len) < 0) | if (write(vty->wfd, buf, len) < 0) |
| { |
{ |
| if (ERRNO_IO_RETRY(errno)) |
if (ERRNO_IO_RETRY(errno)) |
| /* Kernel buffer is full, probably too much debugging output, so just |
/* Kernel buffer is full, probably too much debugging output, so just |
|
Line 400 vty_command (struct vty *vty, char *buf)
|
Line 401 vty_command (struct vty *vty, char *buf)
|
| int ret; |
int ret; |
| vector vline; |
vector vline; |
| const char *protocolname; |
const char *protocolname; |
| |
char *cp; |
| |
|
| |
/* |
| |
* Log non empty command lines |
| |
*/ |
| |
cp = buf; |
| |
if (cp != NULL) |
| |
{ |
| |
/* Skip white spaces. */ |
| |
while (isspace ((int) *cp) && *cp != '\0') |
| |
cp++; |
| |
} |
| |
if (cp != NULL && *cp != '\0') |
| |
{ |
| |
unsigned i; |
| |
char vty_str[VTY_BUFSIZ]; |
| |
char prompt_str[VTY_BUFSIZ]; |
| |
|
| |
/* format the base vty info */ |
| |
snprintf(vty_str, sizeof(vty_str), "vty[??]@%s", vty->address); |
| |
if (vty) |
| |
for (i = 0; i < vector_active (vtyvec); i++) |
| |
if ((vty == vector_slot (vtyvec, i))) |
| |
{ |
| |
snprintf(vty_str, sizeof(vty_str), "vty[%d]@%s", |
| |
i, vty->address); |
| |
break; |
| |
} |
| |
|
| |
/* format the prompt */ |
| |
snprintf(prompt_str, sizeof(prompt_str), cmd_prompt (vty->node), vty_str); |
| |
|
| |
/* now log the command */ |
| |
zlog(NULL, LOG_NOTICE, "%s%s", prompt_str, buf); |
| |
} |
| /* Split readline string up into the vector */ |
/* Split readline string up into the vector */ |
| vline = cmd_make_strvec (buf); |
vline = cmd_make_strvec (buf); |
| |
|
|
Line 455 vty_command (struct vty *vty, char *buf)
|
Line 490 vty_command (struct vty *vty, char *buf)
|
| |
|
| return ret; |
return ret; |
| } |
} |
| |
| static const char telnet_backward_char = 0x08; |
static const char telnet_backward_char = 0x08; |
| static const char telnet_space_char = ' '; |
static const char telnet_space_char = ' '; |
| |
|
|
Line 702 vty_end_config (struct vty *vty)
|
Line 737 vty_end_config (struct vty *vty)
|
| case BABEL_NODE: |
case BABEL_NODE: |
| case BGP_NODE: |
case BGP_NODE: |
| case BGP_VPNV4_NODE: |
case BGP_VPNV4_NODE: |
| |
case BGP_VPNV6_NODE: |
| |
case BGP_ENCAP_NODE: |
| |
case BGP_ENCAPV6_NODE: |
| case BGP_IPV4_NODE: |
case BGP_IPV4_NODE: |
| case BGP_IPV4M_NODE: |
case BGP_IPV4M_NODE: |
| case BGP_IPV6_NODE: |
case BGP_IPV6_NODE: |
|
Line 713 vty_end_config (struct vty *vty)
|
Line 751 vty_end_config (struct vty *vty)
|
| case KEYCHAIN_NODE: |
case KEYCHAIN_NODE: |
| case KEYCHAIN_KEY_NODE: |
case KEYCHAIN_KEY_NODE: |
| case MASC_NODE: |
case MASC_NODE: |
| |
case PIM_NODE: |
| case VTY_NODE: |
case VTY_NODE: |
| vty_config_unlock (vty); |
vty_config_unlock (vty); |
| vty->node = ENABLE_NODE; |
vty->node = ENABLE_NODE; |
|
Line 869 vty_complete_command (struct vty *vty)
|
Line 908 vty_complete_command (struct vty *vty)
|
| |
|
| /* In case of 'help \t'. */ |
/* In case of 'help \t'. */ |
| if (isspace ((int) vty->buf[vty->length - 1])) |
if (isspace ((int) vty->buf[vty->length - 1])) |
| vector_set (vline, '\0'); | vector_set (vline, NULL); |
| |
|
| matched = cmd_complete_command (vline, vty, &ret); | matched = cmd_complete_command_lib (vline, vty, &ret, 1); |
| |
|
| cmd_free_strvec (vline); |
cmd_free_strvec (vline); |
| |
|
|
Line 931 vty_complete_command (struct vty *vty)
|
Line 970 vty_complete_command (struct vty *vty)
|
| |
|
| static void |
static void |
| vty_describe_fold (struct vty *vty, int cmd_width, |
vty_describe_fold (struct vty *vty, int cmd_width, |
| unsigned int desc_width, struct desc *desc) | unsigned int desc_width, struct cmd_token *token) |
| { |
{ |
| char *buf; |
char *buf; |
| const char *cmd, *p; |
const char *cmd, *p; |
| int pos; |
int pos; |
| |
|
| cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd; | cmd = token->cmd[0] == '.' ? token->cmd + 1 : token->cmd; |
| |
|
| if (desc_width <= 0) |
if (desc_width <= 0) |
| { |
{ |
| vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE); | vty_out (vty, " %-*s %s%s", cmd_width, cmd, token->desc, VTY_NEWLINE); |
| return; |
return; |
| } |
} |
| |
|
| buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1); | buf = XCALLOC (MTYPE_TMP, strlen (token->desc) + 1); |
| |
|
| for (p = desc->str; strlen (p) > desc_width; p += pos + 1) | for (p = token->desc; strlen (p) > desc_width; p += pos + 1) |
| { |
{ |
| for (pos = desc_width; pos > 0; pos--) |
for (pos = desc_width; pos > 0; pos--) |
| if (*(p + pos) == ' ') |
if (*(p + pos) == ' ') |
|
Line 976 vty_describe_command (struct vty *vty)
|
Line 1015 vty_describe_command (struct vty *vty)
|
| vector vline; |
vector vline; |
| vector describe; |
vector describe; |
| unsigned int i, width, desc_width; |
unsigned int i, width, desc_width; |
| struct desc *desc, *desc_cr = NULL; | struct cmd_token *token, *token_cr = NULL; |
| |
|
| vline = cmd_make_strvec (vty->buf); |
vline = cmd_make_strvec (vty->buf); |
| |
|
|
Line 984 vty_describe_command (struct vty *vty)
|
Line 1023 vty_describe_command (struct vty *vty)
|
| if (vline == NULL) |
if (vline == NULL) |
| { |
{ |
| vline = vector_init (1); |
vline = vector_init (1); |
| vector_set (vline, '\0'); | vector_set (vline, NULL); |
| } |
} |
| else |
else |
| if (isspace ((int) vty->buf[vty->length - 1])) |
if (isspace ((int) vty->buf[vty->length - 1])) |
| vector_set (vline, '\0'); | vector_set (vline, NULL); |
| |
|
| describe = cmd_describe_command (vline, vty, &ret); |
describe = cmd_describe_command (vline, vty, &ret); |
| |
|
|
Line 1010 vty_describe_command (struct vty *vty)
|
Line 1049 vty_describe_command (struct vty *vty)
|
| /* Get width of command string. */ |
/* Get width of command string. */ |
| width = 0; |
width = 0; |
| for (i = 0; i < vector_active (describe); i++) |
for (i = 0; i < vector_active (describe); i++) |
| if ((desc = vector_slot (describe, i)) != NULL) | if ((token = vector_slot (describe, i)) != NULL) |
| { |
{ |
| unsigned int len; |
unsigned int len; |
| |
|
| if (desc->cmd[0] == '\0') | if (token->cmd[0] == '\0') |
| continue; |
continue; |
| |
|
| len = strlen (desc->cmd); | len = strlen (token->cmd); |
| if (desc->cmd[0] == '.') | if (token->cmd[0] == '.') |
| len--; |
len--; |
| |
|
| if (width < len) |
if (width < len) |
|
Line 1030 vty_describe_command (struct vty *vty)
|
Line 1069 vty_describe_command (struct vty *vty)
|
| |
|
| /* Print out description. */ |
/* Print out description. */ |
| for (i = 0; i < vector_active (describe); i++) |
for (i = 0; i < vector_active (describe); i++) |
| if ((desc = vector_slot (describe, i)) != NULL) | if ((token = vector_slot (describe, i)) != NULL) |
| { |
{ |
| if (desc->cmd[0] == '\0') | if (token->cmd[0] == '\0') |
| continue; |
continue; |
| |
|
| if (strcmp (desc->cmd, command_cr) == 0) | if (strcmp (token->cmd, command_cr) == 0) |
| { |
{ |
| desc_cr = desc; | token_cr = token; |
| continue; |
continue; |
| } |
} |
| |
|
| if (!desc->str) | if (!token->desc) |
| vty_out (vty, " %-s%s", |
vty_out (vty, " %-s%s", |
| desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, | token->cmd[0] == '.' ? token->cmd + 1 : token->cmd, |
| VTY_NEWLINE); |
VTY_NEWLINE); |
| else if (desc_width >= strlen (desc->str)) | else if (desc_width >= strlen (token->desc)) |
| vty_out (vty, " %-*s %s%s", width, |
vty_out (vty, " %-*s %s%s", width, |
| desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, | token->cmd[0] == '.' ? token->cmd + 1 : token->cmd, |
| desc->str, VTY_NEWLINE); | token->desc, VTY_NEWLINE); |
| else |
else |
| vty_describe_fold (vty, width, desc_width, desc); | vty_describe_fold (vty, width, desc_width, token); |
| |
|
| #if 0 |
#if 0 |
| vty_out (vty, " %-*s %s%s", width |
vty_out (vty, " %-*s %s%s", width |
|
Line 1059 vty_describe_command (struct vty *vty)
|
Line 1098 vty_describe_command (struct vty *vty)
|
| #endif /* 0 */ |
#endif /* 0 */ |
| } |
} |
| |
|
| if ((desc = desc_cr)) | if ((token = token_cr)) |
| { |
{ |
| if (!desc->str) | if (!token->desc) |
| vty_out (vty, " %-s%s", |
vty_out (vty, " %-s%s", |
| desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, | token->cmd[0] == '.' ? token->cmd + 1 : token->cmd, |
| VTY_NEWLINE); |
VTY_NEWLINE); |
| else if (desc_width >= strlen (desc->str)) | else if (desc_width >= strlen (token->desc)) |
| vty_out (vty, " %-*s %s%s", width, |
vty_out (vty, " %-*s %s%s", width, |
| desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, | token->cmd[0] == '.' ? token->cmd + 1 : token->cmd, |
| desc->str, VTY_NEWLINE); | token->desc, VTY_NEWLINE); |
| else |
else |
| vty_describe_fold (vty, width, desc_width, desc); | vty_describe_fold (vty, width, desc_width, token); |
| } |
} |
| |
|
| out: |
out: |
|
Line 1117 vty_stop_input (struct vty *vty)
|
Line 1156 vty_stop_input (struct vty *vty)
|
| case KEYCHAIN_NODE: |
case KEYCHAIN_NODE: |
| case KEYCHAIN_KEY_NODE: |
case KEYCHAIN_KEY_NODE: |
| case MASC_NODE: |
case MASC_NODE: |
| |
case PIM_NODE: |
| case VTY_NODE: |
case VTY_NODE: |
| vty_config_unlock (vty); |
vty_config_unlock (vty); |
| vty->node = ENABLE_NODE; |
vty->node = ENABLE_NODE; |
|
Line 1361 vty_read (struct thread *thread)
|
Line 1401 vty_read (struct thread *thread)
|
| vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ |
vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ |
| zlog_warn("%s: read error on vty client fd %d, closing: %s", |
zlog_warn("%s: read error on vty client fd %d, closing: %s", |
| __func__, vty->fd, safe_strerror(errno)); |
__func__, vty->fd, safe_strerror(errno)); |
| |
buffer_reset(vty->obuf); |
| } |
} |
| buffer_reset(vty->obuf); |
|
| vty->status = VTY_CLOSE; |
vty->status = VTY_CLOSE; |
| } |
} |
| |
|
|
Line 1540 vty_read (struct thread *thread)
|
Line 1580 vty_read (struct thread *thread)
|
| vty_close (vty); |
vty_close (vty); |
| else |
else |
| { |
{ |
| vty_event (VTY_WRITE, vty_sock, vty); | vty_event (VTY_WRITE, vty->wfd, vty); |
| vty_event (VTY_READ, vty_sock, vty); |
vty_event (VTY_READ, vty_sock, vty); |
| } |
} |
| return 0; |
return 0; |
|
Line 1568 vty_flush (struct thread *thread)
|
Line 1608 vty_flush (struct thread *thread)
|
| erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE)); |
erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE)); |
| |
|
| /* N.B. if width is 0, that means we don't know the window size. */ |
/* N.B. if width is 0, that means we don't know the window size. */ |
| if ((vty->lines == 0) || (vty->width == 0)) | if ((vty->lines == 0) || (vty->width == 0) || (vty->height == 0)) |
| flushrc = buffer_flush_available(vty->obuf, vty->fd); | flushrc = buffer_flush_available(vty->obuf, vty_sock); |
| else if (vty->status == VTY_MORELINE) |
else if (vty->status == VTY_MORELINE) |
| flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width, | flushrc = buffer_flush_window(vty->obuf, vty_sock, vty->width, |
| 1, erase, 0); |
1, erase, 0); |
| else |
else |
| flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width, | flushrc = buffer_flush_window(vty->obuf, vty_sock, vty->width, |
| vty->lines >= 0 ? vty->lines : |
vty->lines >= 0 ? vty->lines : |
| vty->height, |
vty->height, |
| erase, 0); |
erase, 0); |
|
Line 1608 vty_flush (struct thread *thread)
|
Line 1648 vty_flush (struct thread *thread)
|
| return 0; |
return 0; |
| } |
} |
| |
|
| /* Create new vty structure. */ | /* allocate and initialise vty */ |
| static struct vty * |
static struct vty * |
| vty_create (int vty_sock, union sockunion *su) | vty_new_init (int vty_sock) |
| { |
{ |
| struct vty *vty; |
struct vty *vty; |
| |
|
| /* Allocate new vty structure and set up default values. */ |
|
| vty = vty_new (); |
vty = vty_new (); |
| vty->fd = vty_sock; |
vty->fd = vty_sock; |
| |
vty->wfd = vty_sock; |
| vty->type = VTY_TERM; |
vty->type = VTY_TERM; |
| vty->address = sockunion_su2str (su); | vty->node = AUTH_NODE; |
| if (no_password_check) | |
| { | |
| if (restricted_mode) | |
| vty->node = RESTRICTED_NODE; | |
| else if (host.advanced) | |
| vty->node = ENABLE_NODE; | |
| else | |
| vty->node = VIEW_NODE; | |
| } | |
| else | |
| vty->node = AUTH_NODE; | |
| vty->fail = 0; |
vty->fail = 0; |
| vty->cp = 0; |
vty->cp = 0; |
| vty_clear_buf (vty); |
vty_clear_buf (vty); |
|
Line 1639 vty_create (int vty_sock, union sockunion *su)
|
Line 1668 vty_create (int vty_sock, union sockunion *su)
|
| vty->hindex = 0; |
vty->hindex = 0; |
| vector_set_index (vtyvec, vty_sock, vty); |
vector_set_index (vtyvec, vty_sock, vty); |
| vty->status = VTY_NORMAL; |
vty->status = VTY_NORMAL; |
| vty->v_timeout = vty_timeout_val; | vty->lines = -1; |
| if (host.lines >= 0) | |
| vty->lines = host.lines; | |
| else | |
| vty->lines = -1; | |
| vty->iac = 0; |
vty->iac = 0; |
| vty->iac_sb_in_progress = 0; |
vty->iac_sb_in_progress = 0; |
| vty->sb_len = 0; |
vty->sb_len = 0; |
| |
|
| |
return vty; |
| |
} |
| |
|
| |
/* Create new vty structure. */ |
| |
static struct vty * |
| |
vty_create (int vty_sock, union sockunion *su) |
| |
{ |
| |
char buf[SU_ADDRSTRLEN]; |
| |
struct vty *vty; |
| |
|
| |
sockunion2str(su, buf, SU_ADDRSTRLEN); |
| |
|
| |
/* Allocate new vty structure and set up default values. */ |
| |
vty = vty_new_init (vty_sock); |
| |
|
| |
/* configurable parameters not part of basic init */ |
| |
vty->v_timeout = vty_timeout_val; |
| |
strcpy (vty->address, buf); |
| |
if (no_password_check) |
| |
{ |
| |
if (restricted_mode) |
| |
vty->node = RESTRICTED_NODE; |
| |
else if (host.advanced) |
| |
vty->node = ENABLE_NODE; |
| |
else |
| |
vty->node = VIEW_NODE; |
| |
} |
| |
if (host.lines >= 0) |
| |
vty->lines = host.lines; |
| |
|
| if (! no_password_check) |
if (! no_password_check) |
| { |
{ |
| /* Vty is not available if password isn't set. */ |
/* Vty is not available if password isn't set. */ |
|
Line 1682 vty_create (int vty_sock, union sockunion *su)
|
Line 1737 vty_create (int vty_sock, union sockunion *su)
|
| return vty; |
return vty; |
| } |
} |
| |
|
| |
/* create vty for stdio */ |
| |
static struct termios stdio_orig_termios; |
| |
static struct vty *stdio_vty = NULL; |
| |
static void (*stdio_vty_atclose)(void); |
| |
|
| |
static void |
| |
vty_stdio_reset (void) |
| |
{ |
| |
if (stdio_vty) |
| |
{ |
| |
tcsetattr (0, TCSANOW, &stdio_orig_termios); |
| |
stdio_vty = NULL; |
| |
|
| |
if (stdio_vty_atclose) |
| |
stdio_vty_atclose (); |
| |
stdio_vty_atclose = NULL; |
| |
} |
| |
} |
| |
|
| |
struct vty * |
| |
vty_stdio (void (*atclose)()) |
| |
{ |
| |
struct vty *vty; |
| |
struct termios termios; |
| |
|
| |
/* refuse creating two vtys on stdio */ |
| |
if (stdio_vty) |
| |
return NULL; |
| |
|
| |
vty = stdio_vty = vty_new_init (0); |
| |
stdio_vty_atclose = atclose; |
| |
vty->wfd = 1; |
| |
|
| |
/* always have stdio vty in a known _unchangeable_ state, don't want config |
| |
* to have any effect here to make sure scripting this works as intended */ |
| |
vty->node = ENABLE_NODE; |
| |
vty->v_timeout = 0; |
| |
strcpy (vty->address, "console"); |
| |
|
| |
if (!tcgetattr (0, &stdio_orig_termios)) |
| |
{ |
| |
termios = stdio_orig_termios; |
| |
termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP |
| |
| INLCR | IGNCR | ICRNL | IXON); |
| |
termios.c_oflag &= ~OPOST; |
| |
termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); |
| |
termios.c_cflag &= ~(CSIZE | PARENB); |
| |
termios.c_cflag |= CS8; |
| |
tcsetattr (0, TCSANOW, &termios); |
| |
} |
| |
|
| |
vty_prompt (vty); |
| |
|
| |
/* Add read/write thread. */ |
| |
vty_event (VTY_WRITE, 1, vty); |
| |
vty_event (VTY_READ, 0, vty); |
| |
|
| |
return vty; |
| |
} |
| |
|
| /* Accept connection from the network. */ |
/* Accept connection from the network. */ |
| static int |
static int |
| vty_accept (struct thread *thread) |
vty_accept (struct thread *thread) |
|
Line 1691 vty_accept (struct thread *thread)
|
Line 1806 vty_accept (struct thread *thread)
|
| int ret; |
int ret; |
| unsigned int on; |
unsigned int on; |
| int accept_sock; |
int accept_sock; |
| struct prefix *p = NULL; | struct prefix p; |
| struct access_list *acl = NULL; |
struct access_list *acl = NULL; |
| char *bufp; | char buf[SU_ADDRSTRLEN]; |
| |
|
| accept_sock = THREAD_FD (thread); |
accept_sock = THREAD_FD (thread); |
| |
|
|
Line 1711 vty_accept (struct thread *thread)
|
Line 1826 vty_accept (struct thread *thread)
|
| } |
} |
| set_nonblocking(vty_sock); |
set_nonblocking(vty_sock); |
| |
|
| p = sockunion2hostprefix (&su); | sockunion2hostprefix (&su, &p); |
| |
|
| /* VTY's accesslist apply. */ |
/* VTY's accesslist apply. */ |
| if (p->family == AF_INET && vty_accesslist_name) | if (p.family == AF_INET && vty_accesslist_name) |
| { |
{ |
| if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) && |
if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) && |
| (access_list_apply (acl, p) == FILTER_DENY)) | (access_list_apply (acl, &p) == FILTER_DENY)) |
| { |
{ |
| char *buf; |
|
| zlog (NULL, LOG_INFO, "Vty connection refused from %s", |
zlog (NULL, LOG_INFO, "Vty connection refused from %s", |
| (buf = sockunion_su2str (&su))); | sockunion2str (&su, buf, SU_ADDRSTRLEN)); |
| free (buf); | |
| close (vty_sock); |
close (vty_sock); |
| |
|
| /* continue accepting connections */ |
/* continue accepting connections */ |
| vty_event (VTY_SERV, accept_sock, NULL); |
vty_event (VTY_SERV, accept_sock, NULL); |
| |
|
| prefix_free (p); |
|
| |
|
| return 0; |
return 0; |
| } |
} |
| } |
} |
| |
|
| #ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
| /* VTY's ipv6 accesslist apply. */ |
/* VTY's ipv6 accesslist apply. */ |
| if (p->family == AF_INET6 && vty_ipv6_accesslist_name) | if (p.family == AF_INET6 && vty_ipv6_accesslist_name) |
| { |
{ |
| if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) && |
if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) && |
| (access_list_apply (acl, p) == FILTER_DENY)) | (access_list_apply (acl, &p) == FILTER_DENY)) |
| { |
{ |
| char *buf; |
|
| zlog (NULL, LOG_INFO, "Vty connection refused from %s", |
zlog (NULL, LOG_INFO, "Vty connection refused from %s", |
| (buf = sockunion_su2str (&su))); | sockunion2str (&su, buf, SU_ADDRSTRLEN)); |
| free (buf); | |
| close (vty_sock); |
close (vty_sock); |
| |
|
| /* continue accepting connections */ |
/* continue accepting connections */ |
| vty_event (VTY_SERV, accept_sock, NULL); |
vty_event (VTY_SERV, accept_sock, NULL); |
| |
|
| prefix_free (p); |
|
| |
|
| return 0; |
return 0; |
| } |
} |
| } |
} |
| #endif /* HAVE_IPV6 */ |
#endif /* HAVE_IPV6 */ |
| |
|
| prefix_free (p); |
|
| |
|
| on = 1; |
on = 1; |
| ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY, |
ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY, |
| (char *) &on, sizeof (on)); |
(char *) &on, sizeof (on)); |
|
Line 1767 vty_accept (struct thread *thread)
|
Line 1872 vty_accept (struct thread *thread)
|
| safe_strerror (errno)); |
safe_strerror (errno)); |
| |
|
| zlog (NULL, LOG_INFO, "Vty connection from %s", |
zlog (NULL, LOG_INFO, "Vty connection from %s", |
| (bufp = sockunion_su2str (&su))); | sockunion2str (&su, buf, SU_ADDRSTRLEN)); |
| if (bufp) | |
| XFREE (MTYPE_TMP, bufp); | |
| |
|
| vty_create (vty_sock, &su); |
vty_create (vty_sock, &su); |
| |
|
| return 0; |
return 0; |
| } |
} |
| |
|
| #if defined(HAVE_IPV6) && !defined(NRL) | #ifdef HAVE_IPV6 |
| static void |
static void |
| vty_serv_sock_addrinfo (const char *hostname, unsigned short port) |
vty_serv_sock_addrinfo (const char *hostname, unsigned short port) |
| { |
{ |
|
Line 1841 vty_serv_sock_addrinfo (const char *hostname, unsigned
|
Line 1944 vty_serv_sock_addrinfo (const char *hostname, unsigned
|
| |
|
| freeaddrinfo (ainfo_save); |
freeaddrinfo (ainfo_save); |
| } |
} |
| #else /* HAVE_IPV6 && ! NRL */ | #else /* HAVE_IPV6 */ |
| |
|
| /* Make vty server socket. */ |
/* Make vty server socket. */ |
| static void |
static void |
|
Line 1859 vty_serv_sock_family (const char* addr, unsigned short
|
Line 1962 vty_serv_sock_family (const char* addr, unsigned short
|
| { |
{ |
| case AF_INET: |
case AF_INET: |
| naddr=&su.sin.sin_addr; |
naddr=&su.sin.sin_addr; |
| |
break; |
| #ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
| case AF_INET6: |
case AF_INET6: |
| naddr=&su.sin6.sin6_addr; |
naddr=&su.sin6.sin6_addr; |
| |
break; |
| #endif |
#endif |
| } |
} |
| |
|
|
Line 1907 vty_serv_sock_family (const char* addr, unsigned short
|
Line 2012 vty_serv_sock_family (const char* addr, unsigned short
|
| /* Add vty server event. */ |
/* Add vty server event. */ |
| vty_event (VTY_SERV, accept_sock, NULL); |
vty_event (VTY_SERV, accept_sock, NULL); |
| } |
} |
| #endif /* HAVE_IPV6 && ! NRL */ | #endif /* HAVE_IPV6 */ |
| |
|
| #ifdef VTYSH |
#ifdef VTYSH |
| /* For sockaddr_un. */ |
/* For sockaddr_un. */ |
|
Line 2021 vtysh_accept (struct thread *thread)
|
Line 2126 vtysh_accept (struct thread *thread)
|
| |
|
| vty = vty_new (); |
vty = vty_new (); |
| vty->fd = sock; |
vty->fd = sock; |
| |
vty->wfd = sock; |
| vty->type = VTY_SHELL_SERV; |
vty->type = VTY_SHELL_SERV; |
| vty->node = VIEW_NODE; |
vty->node = VIEW_NODE; |
| |
|
|
Line 2032 vtysh_accept (struct thread *thread)
|
Line 2138 vtysh_accept (struct thread *thread)
|
| static int |
static int |
| vtysh_flush(struct vty *vty) |
vtysh_flush(struct vty *vty) |
| { |
{ |
| switch (buffer_flush_available(vty->obuf, vty->fd)) | switch (buffer_flush_available(vty->obuf, vty->wfd)) |
| { |
{ |
| case BUFFER_PENDING: |
case BUFFER_PENDING: |
| vty_event(VTYSH_WRITE, vty->fd, vty); | vty_event(VTYSH_WRITE, vty->wfd, vty); |
| break; |
break; |
| case BUFFER_ERROR: |
case BUFFER_ERROR: |
| vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ |
vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ |
|
Line 2142 vty_serv_sock (const char *addr, unsigned short port,
|
Line 2248 vty_serv_sock (const char *addr, unsigned short port,
|
| { |
{ |
| |
|
| #ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
| #ifdef NRL |
|
| vty_serv_sock_family (addr, port, AF_INET); |
|
| vty_serv_sock_family (addr, port, AF_INET6); |
|
| #else /* ! NRL */ |
|
| vty_serv_sock_addrinfo (addr, port); |
vty_serv_sock_addrinfo (addr, port); |
| #endif /* NRL*/ |
|
| #else /* ! HAVE_IPV6 */ |
#else /* ! HAVE_IPV6 */ |
| vty_serv_sock_family (addr,port, AF_INET); |
vty_serv_sock_family (addr,port, AF_INET); |
| #endif /* HAVE_IPV6 */ |
#endif /* HAVE_IPV6 */ |
|
Line 2176 vty_close (struct vty *vty)
|
Line 2277 vty_close (struct vty *vty)
|
| thread_cancel (vty->t_timeout); |
thread_cancel (vty->t_timeout); |
| |
|
| /* Flush buffer. */ |
/* Flush buffer. */ |
| buffer_flush_all (vty->obuf, vty->fd); | buffer_flush_all (vty->obuf, vty->wfd); |
| |
|
| /* Free input buffer. */ |
/* Free input buffer. */ |
| buffer_free (vty->obuf); |
buffer_free (vty->obuf); |
|
Line 2192 vty_close (struct vty *vty)
|
Line 2293 vty_close (struct vty *vty)
|
| /* Close socket. */ |
/* Close socket. */ |
| if (vty->fd > 0) |
if (vty->fd > 0) |
| close (vty->fd); |
close (vty->fd); |
| |
else |
| |
vty_stdio_reset (); |
| |
|
| if (vty->address) |
|
| XFREE (MTYPE_TMP, vty->address); |
|
| if (vty->buf) |
if (vty->buf) |
| XFREE (MTYPE_VTY, vty->buf); |
XFREE (MTYPE_VTY, vty->buf); |
| |
|
|
Line 2232 vty_read_file (FILE *confp)
|
Line 2333 vty_read_file (FILE *confp)
|
| { |
{ |
| int ret; |
int ret; |
| struct vty *vty; |
struct vty *vty; |
| |
unsigned int line_num = 0; |
| |
|
| vty = vty_new (); |
vty = vty_new (); |
| vty->fd = 0; /* stdout */ | vty->wfd = dup(STDERR_FILENO); /* vty_close() will close this */ |
| vty->type = VTY_TERM; | if (vty->wfd < 0) |
| | { |
| | /* Fine, we couldn't make a new fd. vty_close doesn't close stdout. */ |
| | vty->wfd = STDOUT_FILENO; |
| | } |
| | vty->fd = STDIN_FILENO; |
| | vty->type = VTY_FILE; |
| vty->node = CONFIG_NODE; |
vty->node = CONFIG_NODE; |
| |
|
| /* Execute configuration file */ |
/* Execute configuration file */ |
| ret = config_from_file (vty, confp); | ret = config_from_file (vty, confp, &line_num); |
| |
|
| |
/* Flush any previous errors before printing messages below */ |
| |
buffer_flush_all (vty->obuf, vty->fd); |
| |
|
| if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) ) |
if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) ) |
| { |
{ |
| switch (ret) |
switch (ret) |
| { |
{ |
| case CMD_ERR_AMBIGUOUS: |
case CMD_ERR_AMBIGUOUS: |
| fprintf (stderr, "Ambiguous command.\n"); | fprintf (stderr, "*** Error reading config: Ambiguous command.\n"); |
| break; |
break; |
| case CMD_ERR_NO_MATCH: |
case CMD_ERR_NO_MATCH: |
| fprintf (stderr, "There is no such command.\n"); | fprintf (stderr, "*** Error reading config: There is no such command.\n"); |
| break; |
break; |
| } |
} |
| fprintf (stderr, "Error occured during reading below line.\n%s\n", | fprintf (stderr, "*** Error occured processing line %u, below:\n%s\n", |
| vty->buf); | line_num, vty->buf); |
| vty_close (vty); |
vty_close (vty); |
| exit (1); |
exit (1); |
| } |
} |
|
Line 2452 vty_log (const char *level, const char *proto_str,
|
Line 2563 vty_log (const char *level, const char *proto_str,
|
| |
|
| /* Async-signal-safe version of vty_log for fixed strings. */ |
/* Async-signal-safe version of vty_log for fixed strings. */ |
| void |
void |
| vty_log_fixed (const char *buf, size_t len) | vty_log_fixed (char *buf, size_t len) |
| { |
{ |
| unsigned int i; |
unsigned int i; |
| struct iovec iov[2]; |
struct iovec iov[2]; |
|
Line 2461 vty_log_fixed (const char *buf, size_t len)
|
Line 2572 vty_log_fixed (const char *buf, size_t len)
|
| if (!vtyvec) |
if (!vtyvec) |
| return; |
return; |
| |
|
| iov[0].iov_base = (void *)buf; | iov[0].iov_base = buf; |
| iov[0].iov_len = len; |
iov[0].iov_len = len; |
| iov[1].iov_base = (void *)"\r\n"; |
iov[1].iov_base = (void *)"\r\n"; |
| iov[1].iov_len = 2; |
iov[1].iov_len = 2; |
|
Line 2472 vty_log_fixed (const char *buf, size_t len)
|
Line 2583 vty_log_fixed (const char *buf, size_t len)
|
| if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor) |
if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor) |
| /* N.B. We don't care about the return code, since process is |
/* N.B. We don't care about the return code, since process is |
| most likely just about to die anyway. */ |
most likely just about to die anyway. */ |
| writev(vty->fd, iov, 2); | writev(vty->wfd, iov, 2); |
| } |
} |
| } |
} |
| |
|
|
Line 2497 vty_config_unlock (struct vty *vty)
|
Line 2608 vty_config_unlock (struct vty *vty)
|
| } |
} |
| return vty->config; |
return vty->config; |
| } |
} |
| |
| /* Master of the threads. */ |
/* Master of the threads. */ |
| static struct thread_master *master; | static struct thread_master *vty_master; |
| |
|
| static void |
static void |
| vty_event (enum event event, int sock, struct vty *vty) |
vty_event (enum event event, int sock, struct vty *vty) |
|
Line 2509 vty_event (enum event event, int sock, struct vty *vty
|
Line 2620 vty_event (enum event event, int sock, struct vty *vty
|
| switch (event) |
switch (event) |
| { |
{ |
| case VTY_SERV: |
case VTY_SERV: |
| vty_serv_thread = thread_add_read (master, vty_accept, vty, sock); | vty_serv_thread = thread_add_read (vty_master, vty_accept, vty, sock); |
| vector_set_index (Vvty_serv_thread, sock, vty_serv_thread); |
vector_set_index (Vvty_serv_thread, sock, vty_serv_thread); |
| break; |
break; |
| #ifdef VTYSH |
#ifdef VTYSH |
| case VTYSH_SERV: |
case VTYSH_SERV: |
| thread_add_read (master, vtysh_accept, vty, sock); | vty_serv_thread = thread_add_read (vty_master, vtysh_accept, vty, sock); |
| | vector_set_index (Vvty_serv_thread, sock, vty_serv_thread); |
| break; |
break; |
| case VTYSH_READ: |
case VTYSH_READ: |
| vty->t_read = thread_add_read (master, vtysh_read, vty, sock); | vty->t_read = thread_add_read (vty_master, vtysh_read, vty, sock); |
| break; |
break; |
| case VTYSH_WRITE: |
case VTYSH_WRITE: |
| vty->t_write = thread_add_write (master, vtysh_write, vty, sock); | vty->t_write = thread_add_write (vty_master, vtysh_write, vty, sock); |
| break; |
break; |
| #endif /* VTYSH */ |
#endif /* VTYSH */ |
| case VTY_READ: |
case VTY_READ: |
| vty->t_read = thread_add_read (master, vty_read, vty, sock); | vty->t_read = thread_add_read (vty_master, vty_read, vty, sock); |
| |
|
| /* Time out treatment. */ |
/* Time out treatment. */ |
| if (vty->v_timeout) |
if (vty->v_timeout) |
|
Line 2532 vty_event (enum event event, int sock, struct vty *vty
|
Line 2644 vty_event (enum event event, int sock, struct vty *vty
|
| if (vty->t_timeout) |
if (vty->t_timeout) |
| thread_cancel (vty->t_timeout); |
thread_cancel (vty->t_timeout); |
| vty->t_timeout = |
vty->t_timeout = |
| thread_add_timer (master, vty_timeout, vty, vty->v_timeout); | thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout); |
| } |
} |
| break; |
break; |
| case VTY_WRITE: |
case VTY_WRITE: |
| if (! vty->t_write) |
if (! vty->t_write) |
| vty->t_write = thread_add_write (master, vty_flush, vty, sock); | vty->t_write = thread_add_write (vty_master, vty_flush, vty, sock); |
| break; |
break; |
| case VTY_TIMEOUT_RESET: |
case VTY_TIMEOUT_RESET: |
| if (vty->t_timeout) |
if (vty->t_timeout) |
|
Line 2548 vty_event (enum event event, int sock, struct vty *vty
|
Line 2660 vty_event (enum event event, int sock, struct vty *vty
|
| if (vty->v_timeout) |
if (vty->v_timeout) |
| { |
{ |
| vty->t_timeout = |
vty->t_timeout = |
| thread_add_timer (master, vty_timeout, vty, vty->v_timeout); | thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout); |
| } |
} |
| break; |
break; |
| } |
} |
| } |
} |
| |
| DEFUN (config_who, |
DEFUN (config_who, |
| config_who_cmd, |
config_who_cmd, |
| "who", |
"who", |
|
Line 2960 vty_init (struct thread_master *master_thread)
|
Line 3072 vty_init (struct thread_master *master_thread)
|
| |
|
| vtyvec = vector_init (VECTOR_MIN_SIZE); |
vtyvec = vector_init (VECTOR_MIN_SIZE); |
| |
|
| master = master_thread; | vty_master = master_thread; |
| | |
| | atexit (vty_stdio_reset); |
| |
|
| /* Initilize server thread vector. */ |
/* Initilize server thread vector. */ |
| Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE); |
Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE); |