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); |