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

 

posted @ 2017-12-26 12:26  elewei  阅读(429)  评论(0)    收藏  举报