nsh 源码流程
makefile
PROG= nsh CFLAGS?=-O CFLAGS+=-Wmissing-prototypes -Wformat -Wall -Wpointer-arith -Wbad-function-cast -I/usr/local/include #-W SRCS=arp.c compile.c main.c genget.c commands.c stats.c kroute.c SRCS+=ctl.c show.c if.c version.c route.c conf.c complete.c ieee80211.c SRCS+=bridge.c tunnel.c media.c sysctl.c passwd.c pfsync.c carp.c SRCS+=trunk.c who.c more.c stringlist.c utils.c sqlite3.c ppp.c SRCS+=nopt.c pflow.c CLEANFILES+=compile.c LDADD=-ledit -ltermcap -lsqlite3 -L/usr/local/lib #-static NOMAN=1 compile.c: compile.sh sh ${.CURDIR}/compile.sh .include <bsd.prog.mk>
main函数流程 nsh.c
判断是否是root用户且将值赋值给全局变量pid,如果不是,打印权限不够。
while 循环 判断
调用getopt函数,判断输入参数
如果是 c 选项
cflag = 1
rc为下一个参数的值
如果是 i 选项
iflag = 1;
rc为下一个参数的值
如果是 v 选项
verbose = 1;
默认 打印帮助信息
arc的值减1, argv指针向前进1
cflag 与 iflag 不能同时为1
如果iflag为真, 调用 rmtemp(SQ3DBFILE) 移除临时文件
rmtemp 定义在头文件extern.h 中, 在ctl.c 文件中实现
创建数据库 sqlite
rtables // 路由表
ctl // 命令表
dhcrelay // dhcp 中继
ipv6linklocal // IPv6 本地链路
lladdr // 链路本地地址
rtadvd // CARP 广播数据包
authkey // 登录认证口令
peerkey // CARP 邻居密钥
top 设置函数跳转
如果收到
SIGWINCH
SIGINT
跳转到此
无限循环
command() 函数 在externs.h 头文件中定义,在commands.c 文件中实现
top 的值为1
pid_t pid;
int main(int argc, char *argv[]) { int top, ch, iflag = 0, cflag = 0; char rc[PATH_MAX]; if(pid = getuid() != 0) printf("%% 权限不够.\n"); while ((ch = getopt(argc, argv, "c:i:v")) != -1) switch (ch) { case 'c': cflag = 1; strlcpy(rc, optarg, PATH_MAX); break; case 'i': iflag = 1; strlcpy(rc, optarg, PATH_MAX); break; case 'v': verbose = 1; break; default: usage(); } argc -= optind; argv += optind; if (cflag && iflag) usage(); if (argc > 0) usage(); if (iflag) rmtemp(SQ3DBFILE); printf("%% 防火墙Shell程序 -- v%s\n", vers); /* 如果数据库未创建,创建临时的数据库 */ if (db_create_table_rtables() < 0) printf("%% database rtables creation failed\n"); if (db_create_table_flag_x("ctl") < 0) printf("%% database ctl creation failed\n"); if (db_create_table_flag_x("dhcprelay") < 0) printf("%% database dhcrelay creation failed\n"); if (db_create_table_flag_x("ipv6linklocal") < 0) printf("%% database ipv6linklocal creation failed\n"); if (db_create_table_flag_x("lladdr") < 0) printf("%% database lladdr creation failed\n"); if (db_create_table_flag_x("rtadvd") < 0) printf("%% database rtadvd creation failed\n"); if (db_create_table_flag_x("authkey") < 0) printf("%% database authkey creation failed\n"); if (db_create_table_flag_x("peerkey") < 0) printf("%% database peerkey creation failed\n"); if (iflag) { char *argv_demote[] = { "group", "carp", "carpdemote", "128" }; char *argv_restore[] = { "no", "group", "carp", "carpdemote", "128" }; priv = 1; group(nitems(argv_demote), argv_demote); cmdrc(rc); group(nitems(argv_restore), argv_restore); exit(0); } if (cflag) { priv = 1; cmdrc(rc); exit(0); } top = setjmp(toplevel) == 0; if (top) { (void)signal(SIGWINCH, setwinsize); (void)signal(SIGINT, (sig_t)intr); (void)setwinsize(0); } else putchar('\n'); for (;;) { command(); top = 1; } /* NOTREACHED */ return 0; }
commands.c
流程:
如果editing为真, editing 初始值为1,在main 函数中定义为全局变量,externs.h 头文件中进行引用
inithist(), 在 complete.c 文件中定义,初始化历史缓存,记录值为100个
initedit() 在 complete.c 文件中定义,全局结构 EditLine 为 命令编辑库中数据结构 libedit库
进入for死循环
如果editing为非真
否则
定义buf数组
buf = el_gets(elc, &num)
(*c->handler) (margc, margv, 0) 调用进入相关模块与函数
void command() { Command *c; // 定义数据结构 Command 在extern.h 头文件中定义 u_int num; if (editing) { inithist(); initedit(); } for (;;) { if (!editing) { printf("%s", cprompt()); if (fgets(line, sizeof(line), stdin) == NULL) { if (feof(stdin) || ferror(stdin)) { printf("\n"); (void) quit(); /* NOTREACHED */ } break; } } else { const char *buf; cursor_pos = NULL; if ((buf = el_gets(elc, &num)) == NULL || num == 0) break; if (buf[--num] == '\n') { if (num == 0) break; } if (num >= sizeof(line)) { printf("%% Input exceeds permitted length\n"); break; } memcpy(line, buf, (size_t)num); line[num] = '\0'; history(histc, &ev, H_ENTER, buf); } if (line[0] == 0) break; makeargv(); if (margv[0] == 0) { break; } if (NO_ARG(margv[0])) c = getcmd(margv[1]); else c = getcmd(margv[0]); if (Ambiguous(c)) { printf("%% Ambiguous command\n"); continue; } if (c == 0) { int val = 1; if (editing) val = el_burrito(elc, margc, margv); if (val) printf("%% Invalid command\n"); continue; } if (NO_ARG(margv[0]) && ! c->nocmd) { printf("%% Invalid command: %s %s\n", margv[0], margv[1]); continue; } if (c->needpriv != 0 && priv != 1) { printf("%% Privilege required\n"); continue; } if (c->modh) strlcpy(hname, c->name, HSIZE); if ((*c->handler) (margc, margv, 0)) { break; } } }
typedef struct cmd { char *name; /* 命令名称 */ char *help; /* 帮助信息 */ char *complete; /* 自动补全提示 */ char **table; /* 下一个自动补全提示 */ int stlen; /* 代码长度 */ int (*handler) (); /* 回调函数 */ int needpriv; /* 是否需要权限执行 */ int nocmd; /* 是否可以执行no命令 */ int modh; /* 是否是cmdrc模式命令? */ } Command;
Command cmdtab[] = { { "hostname", hostnamehelp, CMPL0 0, 0, hostname, 1, 0, 0 }, { "interface", interfacehelp, CMPL(i) 0, 0, interface, 1, 1, 1 }, { "rtable", rtablehelp, CMPL0 0, 0, rtable, 0, 1, 2 }, { "group", grouphelp, CMPL0 0, 0, group, 1, 1, 0 }, { "arp", arphelp, CMPL0 0, 0, arpset, 1, 1, 0 }, { "proxy-arp", parphelp, CMPL0 0, 0, arpset, 1, 1, 0 }, { "bridge", bridgehelp, CMPL(i) 0, 0, interface, 1, 0, 1 }, { "show", showhelp, CMPL(ta) (char **)showlist, sizeof(Menu), showcmd, 0, 0, 0 }, { "ip", iphelp, CMPL(ta) (char **)iptab, sizeof(Menu), ipcmd, 1, 1, 0 }, { "ip6", ip6help, CMPL(ta) (char **)ip6tab, sizeof(Menu), ipcmd, 1, 1, 0 }, { "mpls", mplshelp, CMPL(ta) (char **)mplstab, sizeof(Menu), ipcmd, 1, 1, 0 }, { "ddb", ddbhelp, CMPL(ta) (char **)ddbtab, sizeof(Menu), ipcmd, 1, 1, 0 }, { "pipex", pipexhelp, CMPL(ta) (char **)pipextab, sizeof(Menu), ipcmd, 1, 1, 0 }, { "flush", flushhelp, CMPL(ta) (char **)flushlist, sizeof(Menu), flushcmd, 1, 0, 0 }, { "enable", enablehelp, CMPL0 0, 0, enable, 0, 0, 0 }, { "disable", disablehelp, CMPL0 0, 0, disable, 1, 0, 0 }, { "route", routehelp, CMPL0 0, 0, route, 1, 1, 0 }, { "pf", pfhelp, CMPL(t) (char **)ctl_pf, ssctl, ctlhandler, 1, 0, 1 }, { "ospf", ospfhelp, CMPL(t) (char **)ctl_ospf, ssctl, ctlhandler, 1, 0, 1 }, { "ospf6", ospf6help, CMPL(t) (char **)ctl_ospf6, ssctl, ctlhandler, 1, 0, 1 }, { "eigrp", eigrphelp, CMPL(t) (char **)ctl_eigrp, ssctl, ctlhandler, 1, 0, 1 }, { "bgp", bgphelp, CMPL(t) (char **)ctl_bgp, ssctl, ctlhandler, 1, 0, 1 }, { "rip", riphelp, CMPL(t) (char **)ctl_rip, ssctl, ctlhandler, 1, 0, 1 }, { "ldp", ldphelp, CMPL(t) (char **)ctl_ldp, ssctl, ctlhandler, 1, 0, 1 }, { "relay", relayhelp, CMPL(t) (char **)ctl_relay, ssctl, ctlhandler, 1, 0, 1 }, { "ipsec", ipsechelp, CMPL(t) (char **)ctl_ipsec, ssctl, ctlhandler, 1, 0, 1 }, { "ike", ikehelp, CMPL(t) (char **)ctl_ike, ssctl, ctlhandler, 1, 0, 1 }, { "dvmrp", dvmrphelp, CMPL(t) (char **)ctl_dvmrp, ssctl, ctlhandler, 1, 0, 1 }, { "rtadv", rtadvhelp, CMPL(t) (char **)ctl_rtadv, ssctl, ctlhandler, 1, 0, 1 }, { "sasync", sasynchelp, CMPL(t) (char **)ctl_sasync, ssctl, ctlhandler, 1, 0, 1 }, { "dhcp", dhcphelp, CMPL(t) (char **)ctl_dhcp, ssctl, ctlhandler, 1, 0, 1 }, { "snmp", snmphelp, CMPL(t) (char **)ctl_snmp, ssctl, ctlhandler, 1, 0, 1 }, { "ldap", ldaphelp, CMPL(t) (char **)ctl_ldap, ssctl, ctlhandler, 1, 0, 1 }, { "smtp", smtphelp, CMPL(t) (char **)ctl_smtp, ssctl, ctlhandler, 1, 0, 1 }, { "sshd", sshdhelp, CMPL(t) (char **)ctl_sshd, ssctl, ctlhandler, 1, 0, 1 }, { "ntp", ntphelp, CMPL(t) (char **)ctl_ntp, ssctl, ctlhandler, 1, 0, 1 }, { "nppp", nppphelp, CMPL(t) (char **)ctl_nppp, ssctl, ctlhandler, 1, 0, 1 }, { "ifstate", ifstatehelp, CMPL(t) (char **)ctl_ifstate, ssctl, ctlhandler, 1, 0, 1 }, { "ftp-proxy", ftpproxyhelp, CMPL(t) (char **)ctl_ftpproxy, ssctl, ctlhandler, 1, 0, 1 }, { "tftp-proxy", tftpproxyhelp, CMPL(t) (char **)ctl_tftpproxy, ssctl, ctlhandler, 1, 0, 1 }, { "tftp", tftphelp, CMPL(t) (char **)ctl_tftp, ssctl, ctlhandler, 1, 0, 1 }, { "dns", dnshelp, CMPL(t) (char **)ctl_dns, ssctl, ctlhandler, 1, 0, 1 }, { "motd", motdhelp, CMPL(t) (char **)ctl_motd, ssctl, ctlhandler, 1, 0, 1 }, { "inet", inethelp, CMPL(t) (char **)ctl_inet, ssctl, ctlhandler, 1, 0, 1 }, { "ping", pinghelp, CMPL0 0, 0, ping, 0, 0, 0 }, { "ping6", ping6help, CMPL0 0, 0, ping6, 0, 0, 0 }, { "traceroute", tracerthelp, CMPL0 0, 0, traceroute, 0, 0, 0 }, { "traceroute6", tracert6help, CMPL0 0, 0, traceroute6, 0, 0, 0 }, { "ssh", sshhelp, CMPL0 0, 0, ssh, 0, 0, 0 }, { "telnet", telnethelp, CMPL0 0, 0, telnet, 0, 0, 0 }, { "reboot", nreboothelp, CMPL0 0, 0, nreboot, 1, 0, 0 }, { "halt", halthelp, CMPL0 0, 0, halt, 1, 0, 0 }, { "write-config", savehelp, CMPL0 0, 0, wr_startup, 1, 0, 0 }, { "verbose", verbosehelp, CMPL0 0, 0, doverbose, 0, 1, 0 }, { "editing", editinghelp, CMPL0 0, 0, doediting, 0, 1, 0 }, { "who", whohelp, CMPL0 0, 0, who, 0, 0, 0 }, { "!", shellhelp, CMPL0 0, 0, shell, 1, 0, 0 }, { "?", helphelp, CMPL(C) 0, 0, help, 0, 0, 0 }, { "quit", quithelp, CMPL0 0, 0, quit, 0, 0, 0 }, { "help", 0, CMPL(C) 0, 0, help, 0, 0, 0 }, { 0, 0, CMPL0 0, 0, 0, 0, 0, 0 } };
接口模块
成功返回0, 失败返回-1
// loopback 0
流程:
static int interface(int argc, char **argv, char *modhvar) { u_int num; int ifs, set = 1; char *tmp; struct intlist *i; /* pointer to current command */ struct ifreq ifr; if (!modhvar) { if (NO_ARG(argv[0])) { argv++; argc--; set = 0; } if (argc != 2) { printf("%% [no] interface <interface name>\n"); return(0); } tmp = argv[1]; } else { /* called from cmdrc(), processing config file rules only */ if (argc == 2 && strcmp(modhvar, argv[1]) == 0) { /* do-nothing */ return(0); } tmp = modhvar; } if (strlen(tmp) > IFNAMSIZ-1) { printf("%% interface name too long\n"); return(0); } ifname[IFNAMSIZ-1] = '\0'; strlcpy(ifname, tmp, IFNAMSIZ); strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ifs = socket(AF_INET, SOCK_DGRAM, 0); // 打开SOCK接口 if (ifs < 0) { printf("%% socket failed: %s\n", strerror(errno)); return(1); } if (!is_valid_ifname(ifname)) { if (set == 0) { printf("%% interface %s not found\n", ifname); close(ifs); return(0); } if (ioctl(ifs, SIOCIFCREATE, &ifr) == -1) { // 调用内核 SIOCIFCREATE 接口 if (errno == EINVAL) printf("%% interface %s not found\n", ifname); else printf("%% unable to create interface %s: %s\n", ifname, strerror(errno)); close(ifs); return(0); } } if (set == 0) { if (ioctl(ifs, SIOCIFDESTROY, &ifr) == -1) { printf("%% unable to remove interface %s: %s\n", ifname, strerror(errno)); } else { /* remove interface routes? */ } close(ifs); return(0); } if (is_bridge(ifs, ifname)) { /* whichlist also used by help, command completion code */ whichlist = Bridgelist; bridge = 1; } else { whichlist = Intlist; bridge = 0; } imr_init(ifname); if (modhvar) { /* direct rcfile -i or -c initialization */ char *argp; if (argc - 1 > NARGS) argc = NARGS; if (argv[0] == 0) return(0); if (NO_ARG(argv[0])) argp = argv[1]; else argp = argv[0]; i = (struct intlist *) genget(argp, (char **) whichlist, sizeof(struct intlist)); if (Ambiguous(i)) { printf("%% Ambiguous command\n"); } else if (i == 0) { printf("%% Invalid command\n"); } else { int save_cli_rtable = cli_rtable; cli_rtable = 0; ((*i->handler) (ifname, ifs, argc, argv)); cli_rtable = save_cli_rtable; } return(0); } /* human at the keyboard */ for (;;) { char *margp; if (!editing) { /* command line editing disabled */ printf("%s", iprompt()); if (fgets(line, sizeof(line), stdin) == NULL) { if (feof(stdin) || ferror(stdin)) { printf("\n"); close(ifs); return(0); } break; } } else { const char *buf; cursor_pos = NULL; if ((buf = el_gets(eli, &num)) == NULL || num == 0) break; if (buf[--num] == '\n') { if (num == 0) break; } if (num >= sizeof(line)) { printf("%% Input exceeds permitted length\n"); break; } memcpy(line, buf, (size_t)num); line[num] = '\0'; history(histi, &ev, H_ENTER, buf); } if (line[0] == 0) break; makeargv(); if (margv[0] == 0) break; if (NO_ARG(margv[0])) margp = margv[1]; else margp = margv[0]; i = (struct intlist *) genget(margp, (char **) whichlist, sizeof(struct intlist)); if (Ambiguous(i)) { printf("%% Ambiguous command\n"); } else if (i == 0) { int val = 1; if (editing) val = el_burrito(eli, margc, margv); if (val) printf("%% Invalid command\n"); } else { int save_cli_rtable = cli_rtable; cli_rtable = 0; if ((*i->handler) (ifname, ifs, margc, margv)) { cli_rtable = save_cli_rtable; break; } cli_rtable = save_cli_rtable; } } close(ifs); return(0); }
ip 模块
/* * ip 数据结构 */ Menu iptab[] = { { "carp", "Allow CARP", CMPL0 0, 0, 0, 0, ipsysctl }, { "carp-log", "CARP Logging Priority", CMPL0 0, 0, 0, 1, ipsysctl }, { "carp-preempt","CARP Virtual Host Preemption", CMPL0 0, 0, 0, 0, ipsysctl }, { "forwarding", "Enable IPv4 Forwarding", CMPL0 0, 0, 0, 0, ipsysctl }, { "mforwarding", "Enable IPv4 Multicast Forwarding", CMPL0 0, 0, 0, 0, ipsysctl }, { "ipip", "Allow IP-in-IP Encapsulation", CMPL0 0, 0, 0, 0, ipsysctl }, { "gre", "Allow Generic Route Encapsulation", CMPL0 0, 0, 0, 0, ipsysctl }, { "wccp", "Allow Web Cache Control Protocol", CMPL0 0, 0, 0, 0, ipsysctl }, { "mobileip", "Allow Mobile IP Encapsulation", CMPL0 0, 0, 0, 0, ipsysctl }, { "etherip", "Allow Ether-IP Encapsulation", CMPL0 0, 0, 0, 0, ipsysctl }, { "ipcomp", "Allow IP Compression", CMPL0 0, 0, 0, 0, ipsysctl }, { "esp", "Allow Encapsulated Security Payload", CMPL0 0, 0, 0, 0, ipsysctl }, { "esp-udpencap", "Allow ESP encapsulation within UDP", CMPL0 0, 0, 0, 0, ipsysctl }, { "esp-udpencap-port","UDP port number for encapsulation", CMPL0 0, 0, 0, 1, ipsysctl }, { "ah", "Allow Authentication Header", CMPL0 0, 0, 0, 0, ipsysctl }, { "sourceroute", "Process Loose/Strict Source Route Options", CMPL0 0, 0, 0, 0, ipsysctl }, { "encdebug", "Enable if_enc debugging", CMPL0 0, 0, 0, 0, ipsysctl }, { "send-redirects", "Send ICMP redirects", CMPL0 0, 0, 0, 0, ipsysctl }, { "ifq-maxlen", "IPv4 ifqueue max length", CMPL0 0, 0, 0, 1, ipsysctl }, { "directed-broadcast", "Allow directed broadcasts", CMPL0 0, 0, 0, 0, ipsysctl }, { "multipath", "Multipath routing", CMPL0 0, 0, 0, 0, ipsysctl }, { "default-mtu", "Default interface MTU", CMPL0 0, 0, 1, 1, ipsysctl }, { "default-ttl", "Set Default IP packet TTL", CMPL0 0, 0, 1, 1, ipsysctl }, { "?", "Options", CMPL0 0, 0, 0, 0, sysctlhelp }, { 0, 0, 0, 0, 0, 0, 0, 0 } };
static int ipcmd(int argc, char **argv) { Menu *i; /* pointer to current command */ struct sysctltab *stab; int set, success = 0; if (NO_ARG(argv[0])) { argv++; argc--; set = 0; } else set = 1; /* * Find ourself in the great divide */ stab = (struct sysctltab *)genget(argv[0], (char **)sysctls, sizeof(struct sysctltab)); if (stab == 0) { printf("%% Invalid argument %s\n", argv[0]); return 0; } else if (Ambiguous(stab)) { printf("%% Ambiguous argument %s\n", argv[0]); return 0; } if (argc < 2) { sysctlhelp(0, NULL, NULL, stab->pf); return 0; } /* * Validate ip argument */ i = (Menu *)genget(argv[1], (char **)stab->table, sizeof(Menu)); if (i == 0) { printf("%% Invalid argument %s\n", argv[1]); return 0; } else if (Ambiguous(i)) { printf("%% Ambiguous argument %s\n", argv[1]); return 0; } if (((i->minarg + 2) > argc) || ((i->maxarg + 2) < argc)) { printf("%% Wrong argument%s to '%s %s' command.\n", argc <= 2 ? "" : "s", argv[0], i->name); return 0; } if (i->handler) success = (*i->handler)(set, argv[1], (i->maxarg > 0) ? argv[2] : 0, stab->pf); return(success); }

浙公网安备 33010602011771号