리눅스 routed 코드에 대해...
리눅스 처음다루는데 대뜸 이걸 분석해보라니 원....
라우팅 관련 routed소스 중 메인함수입니다...
분석하는데 도움을 주세요...
char copyright[] =
"@(#) Copyright (c) 1983, 1988, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#if !defined(lint)
static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/5/93";
#else
static char rcsid[] = "$OpenBSD: main.c,v 1.19 2005/03/23 18:06:07 jmc Exp $";
#endif
#include "defs.h"
#include "pathnames.h"
#ifdef sgi
#include "math.h"
#endif
#include
#include
#include
#include
pid_t mypid;
naddr myaddr; /* system address */
char myname[MAXHOSTNAMELEN];
int supplier; /* supply or broadcast updates */
int supplier_set;
int ipforwarding = 1; /* kernel forwarding on */
int default_gateway; /* 1=advertise default */
int background = 1;
int ridhosts; /* 1=reduce host routes */
int mhome; /* 1=want multi-homed host route */
int advertise_mhome; /* 1=must continue adverising it */
int auth_ok = 1; /* 1=ignore auth if we do not care */
struct timeval epoch; /* when started */
struct timeval clk, prev_clk;
struct timeval now; /* current idea of time */
time_t now_stale;
time_t now_expire;
time_t now_garbage;
struct timeval next_bcast; /* next general broadcast */
struct timeval no_flash = {EPOCH+SUPPLY_INTERVAL}; /* inhibit flash update */
fd_set *fdbitsp;
int sock_max;
int rip_sock = -1; /* RIP socket */
struct interface *rip_sock_mcast; /* current multicast interface */
int rt_sock; /* routing socket */
int rt_sock_seqno;
static int get_rip_sock(naddr, int);
static void timevalsub(struct timeval *, struct timeval *, struct timeval *);
int
main(int argc,
char *argv[])
{
int n, mib[4], off;
size_t len;
char *p, *q;
struct timeval wtime, t2;
time_t dt;
fd_set *ibitsp = NULL;
naddr p_addr, p_mask;
struct interface *ifp;
struct parm parm;
char *tracename = 0;
openlog("routed", LOG_PID | LOG_ODELAY, LOG_DAEMON); //프로그램 이름:routed, 소켓을 만듬
ftrace = stdout;
gettimeofday(&clk, 0); //현재 시스템 시간(마이크로초)
prev_clk = clk;
epoch = clk;
epoch.tv_sec -= EPOCH; //EPOCH=bias time
now.tv_sec = EPOCH;
now_stale = EPOCH - STALE_TIME;
now_expire = EPOCH - EXPIRE_TIME;
now_garbage = EPOCH - GARBAGE_TIME;
wtime.tv_sec = 0;
(void)gethostname(myname, sizeof(myname));
(void)gethost(myname, &myaddr);
while ((n = getopt(argc, argv, "sqdghmAtT:F:P:")) != -1) {
switch (n) {
case 's':
supplier = 1;
supplier_set = 1;
break;
case 'q':
supplier = 0;
supplier_set = 1;
break;
case 'd':
background = 0;
break;
case 'g':
bzero(&parm, sizeof(parm));
parm.parm_d_metric = 1;
p = check_parms(&parm);
if (p != 0)
msglog("bad -g: %s", p);
else
default_gateway = 1;
break;
case 'h': /* suppress extra host routes */
ridhosts = 1;
break;
case 'm': /* advertise host route */
mhome = 1; /* on multi-homed hosts */
break;
case 'A':
/* Ignore authentication if we do not care.
* Crazy as it is, that is what RFC 1723 requires.
*/
auth_ok = 0;
break;
case 't':
new_tracelevel++;
break;
case 'T':
tracename = optarg;
break;
case 'F': /* minimal routes for SLIP */
n = HOPCNT_INFINITY-2;
p = strchr(optarg,',');
if (p && *p != '\0') {
n = (int)strtoul(p+1, &q, 0);
if (*q == '\0'
&& n <= HOPCNT_INFINITY-1
&& n >= 1)
*p = '\0';
}
if (!getnet(optarg, &p_addr, &p_mask)) {
msglog("bad network; \"-F %s\"",
optarg);
break;
}
bzero(&parm, sizeof(parm));
parm.parm_addr_h = p_addr;
parm.parm_mask = p_mask;
parm.parm_d_metric = n;
p = check_parms(&parm);
if (p != 0)
msglog("bad -F: %s", p);
break;
case 'P':
/* handle arbirary, (usually) per-interface
* parameters.
*/
p = parse_parms(optarg);
if (p != 0)
msglog("bad \"%s\" in \"%s\"",
p, optarg);
break;
default:
goto usage;
}
}
argc -= optind;
argv += optind;
if (tracename == 0 && argc >= 1) {
tracename = *argv++;
argc--;
}
if (argc != 0) {
usage:
logbad(0, "usage: routed [-Adghmqst] [-F net[/mask][,metric]]"
" [-P parms] [-T tracefile]");
}
if (geteuid() != 0)
logbad(0, "requires UID 0");
mib[0] = CTL_NET;
mib[1] = PF_INET;
mib[2] = IPPROTO_IP;
mib[3] = IPCTL_FORWARDING;
len = sizeof(ipforwarding);
if (sysctl(mib, 4, &ipforwarding, &len, 0, 0) < 0)
LOGERR("sysctl(IPCTL_FORWARDING)");
if (!ipforwarding) {
if (supplier)
msglog("-s incompatible with ipforwarding=0");
if (default_gateway) {
msglog("-g incompatible with ipforwarding=0");
default_gateway = 0;
}
supplier = 0;
supplier_set = 1;
}
if (default_gateway) {
if (supplier_set && !supplier) {
msglog("-g and -q incompatible");
} else {
supplier = 1;
supplier_set = 1;
}
}
signal(SIGALRM, sigalrm);
if (!background)
signal(SIGHUP, sigterm); /* SIGHUP fatal during debugging */
else
signal(SIGHUP, SIG_IGN);
signal(SIGTERM, sigterm);
signal(SIGINT, sigterm);
signal(SIGUSR1, sigtrace_on);
signal(SIGUSR2, sigtrace_off);
/* get into the background */
if (background) {
#ifdef sgi
if (0 > _daemonize(_DF_NOCHDIR,
new_tracelevel == 0 ? -1 :
_FILENO,
new_tracelevel == 0 ? -1 : STDERR_FILENO,
-1))
BADERR(0, "_daemonize()");
#else
if (daemon(1, 1) < 0)
BADERR(0,"daemon()");
#endif
}
mypid = getpid();
/* prepare socket connected to the kernel.
*/
rt_sock = socket(AF_ROUTE, SOCK_RAW, 0);
if (rt_sock < 0)
BADERR(1,"rt_sock = socket()");
if (fcntl(rt_sock, F_SETFL, O_NONBLOCK) == -1)
logbad(1, "fcntl(rt_sock) O_NONBLOCK: %s", strerror(errno));
off = 0;
if (setsockopt(rt_sock, SOL_SOCKET,SO_USELOOPBACK,
&off,sizeof(off)) < 0)
LOGERR("setsockopt(SO_USELOOPBACK,0)");
fix_select();
if (background && new_tracelevel == 0)
ftrace = 0;
if (tracename != 0) {
trace_on(tracename, 1);
if (new_tracelevel == 0) /* use stdout if file is bad */
new_tracelevel = 1;
}
set_tracelevel();
/* initialize radix tree */
rtinit();
/* Pick a random part of the second for our output to minimize
* collisions.
*
* Start broadcasting after hearing from other routers, and
* at a random time so a bunch of systems do not get synchronized
* after a power failure.
*/
intvl_random(&next_bcast, EPOCH+MIN_WAITTIME, EPOCH+SUPPLY_INTERVAL);
age_timer.tv_usec = next_bcast.tv_usec;
age_timer.tv_sec = EPOCH+MIN_WAITTIME;
rdisc_timer = next_bcast;
ifinit_timer.tv_usec = next_bcast.tv_usec;
/* Collect an initial view of the world by checking the interface
* configuration and the kludge file.
*/
gwkludge();
ifinit();
flush_kern();
/* Ask for routes */
rip_query();
if (!supplier)
rdisc_sol();
/* Loop forever, listening and broadcasting.
*/
for (;;) {
prev_clk = clk;
gettimeofday(&clk, 0);
timevalsub(&t2, &clk, &prev_clk);
if (t2.tv_sec < 0
|| t2.tv_sec > wtime.tv_sec + 5) {
/* Deal with time changes before other housekeeping to
* keep everything straight.
*/
dt = t2.tv_sec;
if (dt > 0)
dt -= wtime.tv_sec;
trace_act("time changed by %d sec\n", dt);
epoch.tv_sec += dt;
}
timevalsub(&now, &clk, &epoch);
now_stale = now.tv_sec - STALE_TIME;
now_expire = now.tv_sec - EXPIRE_TIME;
now_garbage = now.tv_sec - GARBAGE_TIME;
/* deal with interrupts that should affect tracing */
set_tracelevel();
if (stopint != 0) {
if (supplier) {
rip_bcast(0);
rdisc_adv();
}
trace_off("exiting with signal %d\n", stopint);
exit(stopint | 128);
}
/* look for new or dead interfaces */
timevalsub(&wtime, &ifinit_timer, &now);
if (wtime.tv_sec <= 0) {
wtime.tv_sec = 0;
ifinit();
rip_query();
continue;
}
/* If it is time, then broadcast our routes.
*/
if (supplier || advertise_mhome) {
timevalsub(&t2, &next_bcast, &now);
if (t2.tv_sec <= 0) {
/* Synchronize the aging and broadcast
* timers to minimize awakenings
*/
age(0);
rip_bcast(0);
/* It is desirable to send routing updates
* regularly. So schedule the next update
* 30 seconds after the previous one was
* secheduled, instead of 30 seconds after
* the previous update was finished.
* Even if we just started after discovering
* a 2nd interface or were otherwise delayed,
* pick a 30-second aniversary of the
* original broadcast time.
*/
n = 1 + (0-t2.tv_sec)/SUPPLY_INTERVAL;
next_bcast.tv_sec += n*SUPPLY_INTERVAL;
continue;
}
if (timercmp(&t2, &wtime, <))
wtime = t2;
}
/* If we need a flash update, either do it now or
* set the delay to end when it is time.
*
* If we are within MIN_WAITTIME seconds of a full update,
* do not bother.
*/
if (need_flash
&& supplier
&& no_flash.tv_sec+MIN_WAITTIME < next_bcast.tv_sec) {
/* accurate to the millisecond */
if (!timercmp(&no_flash, &now, >))
rip_bcast(1);
timevalsub(&t2, &no_flash, &now);
if (timercmp(&t2, &wtime, <))
wtime = t2;
}
/* trigger the main aging timer.
*/
timevalsub(&t2, &age_timer, &now);
if (t2.tv_sec <= 0) {
age(0);
continue;
}
if (timercmp(&t2, &wtime, <))
wtime = t2;
/* update the kernel routing table
*/
timevalsub(&t2, &need_kern, &now);
if (t2.tv_sec <= 0) {
age(0);
continue;
}
if (timercmp(&t2, &wtime, <))
wtime = t2;
/* take care of router discovery,
* but do it to the millisecond
*/
if (!timercmp(&rdisc_timer, &now, >)) {
rdisc_age(0);
continue;
}
timevalsub(&t2, &rdisc_timer, &now);
if (timercmp(&t2, &wtime, <))
wtime = t2;
/* wait for input or a timer to expire.
*/
trace_flush();
if (ibitsp)
free(ibitsp);
ibitsp = (fd_set *)calloc(howmany(sock_max, NFDBITS),
sizeof(fd_mask));
if (ibitsp == NULL)
err(1, "calloc");
memcpy(ibitsp, fdbitsp, howmany(sock_max, NFDBITS) *
sizeof(fd_mask));
n = select(sock_max, ibitsp, 0, 0, &wtime);
if (n <= 0) {
if (n < 0 && errno != EINTR && errno != EAGAIN)
BADERR(1,"select");
continue;
}
if (FD_ISSET(rt_sock, ibitsp)) {
read_rt();
n--;
}
if (rdisc_sock >= 0 && FD_ISSET(rdisc_sock, ibitsp)) {
read_d();
n--;
}
if (rip_sock >= 0 && FD_ISSET(rip_sock, ibitsp)) {
read_rip(rip_sock, 0);
n--;
}
for (ifp = ifnet; n > 0 && 0 != ifp; ifp = ifp->int_next) {
if (ifp->int_rip_sock >= 0
&& FD_ISSET(ifp->int_rip_sock, ibitsp)) {
read_rip(ifp->int_rip_sock, ifp);
n--;
}
}
}
}
/* ARGSUSED */
void
sigalrm(int sig)
{
/* Historically, SIGALRM would cause the daemon to check for
* new and broken interfaces.
*/
ifinit_timer.tv_sec = now.tv_sec;
trace_act("SIGALRM\n"); /* XXX signal race */
}
/* watch for fatal signals */
void
sigterm(int sig)
{
stopint = sig;
(void)signal(sig, SIG_DFL); /* catch it only once */
}
void
fix_select(void)
{
struct interface *ifp;
sock_max = 0;
if (sock_max <= rt_sock)
sock_max = rt_sock+1;
if (rip_sock >= 0 && sock_max <= rip_sock)
sock_max = rip_sock+1;
for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
if (ifp->int_rip_sock >= 0 && sock_max <= ifp->int_rip_sock)
sock_max = ifp->int_rip_sock+1;
}
if (rdisc_sock >= 0 && sock_max <= rdisc_sock)
sock_max = rdisc_sock+1;
if (fdbitsp)
free(fdbitsp);
fdbitsp = (fd_set *)calloc(howmany(sock_max, NFDBITS),
sizeof(fd_mask));
if (fdbitsp == NULL)
err(1, "calloc");
FD_SET(rt_sock, fdbitsp);
if (rip_sock >= 0)
FD_SET(rip_sock, fdbitsp);
for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
if (ifp->int_rip_sock >= 0)
FD_SET(ifp->int_rip_sock, fdbitsp);
}
if (rdisc_sock >= 0)
FD_SET(rdisc_sock, fdbitsp);
}
void
fix_sock(int sock,
char *name)
{
int on;
#define MIN_SOCKBUF (4*1024)
static int rbuf;
if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
logbad(1, "fcntl(%s) O_NONBLOCK: %s",
name, strerror(errno));
on = 1;
if (setsockopt(sock, SOL_SOCKET,SO_BROADCAST,
&on,sizeof(on)) < 0)
msglog("setsockopt(%s,SO_BROADCAST): %s",
name, strerror(errno));
if (rbuf >= MIN_SOCKBUF) {
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
&rbuf, sizeof(rbuf)) < 0)
msglog("setsockopt(%s,SO_RCVBUF=%d): %s",
name, rbuf, strerror(errno));
} else {
for (rbuf = 60*1024; ; rbuf -= 4096) {
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
&rbuf, sizeof(rbuf)) == 0) {
trace_act("RCVBUF=%d\n", rbuf);
break;
}
if (rbuf < MIN_SOCKBUF) {
msglog("setsockopt(%s,SO_RCVBUF = %d): %s",
name, rbuf, strerror(errno));
break;
}
}
}
}
/* get a rip socket
*/
static int /* <0 or file descriptor */
get_rip_sock(naddr addr,
int serious) /* 1=failure to bind is serious */
{
struct sockaddr_in sin;
unsigned char ttl;
int s;
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
BADERR(1,"rip_sock = socket()");
bzero(&sin,sizeof(sin));
#ifdef _HAVE_SIN_LEN
sin.sin_len = sizeof(sin);
#endif
sin.sin_family = AF_INET;
sin.sin_port = htons(RIP_PORT);
sin.sin_addr.s_addr = addr;
if (bind(s, (struct sockaddr *)&sin,sizeof(sin)) < 0) {
if (serious)
BADERR(errno != EADDRINUSE, "bind(rip_sock)");
return -1;
}
fix_sock(s,"rip_sock");
ttl = 1;
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,
&ttl, sizeof(ttl)) < 0)
DBGERR(1,"rip_sock setsockopt(IP_MULTICAST_TTL)");
return s;
}
/* turn off main RIP socket */
void
rip_off(void)
{
struct interface *ifp;
naddr addr;
if (rip_sock >= 0 && !mhome) {
trace_act("turn off RIP\n");
(void)close(rip_sock);
rip_sock = -1;
/* get non-broadcast sockets to listen to queries.
*/
for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
if (ifp->int_rip_sock < 0
&& !(ifp->int_state & IS_ALIAS)) {
addr = ((ifp->int_if_flags & IFF_POINTOPOINT)
? ifp->int_dstaddr
: ifp->int_addr);
ifp->int_rip_sock = get_rip_sock(addr, 0);
}
}
fix_select();
age(0);
}
}
/* turn on RIP multicast input via an interface
*/
static void
rip_mcast_on(struct interface *ifp)
{
struct ip_mreq m;
if (!IS_RIP_IN_OFF(ifp->int_state)
&& (ifp->int_if_flags & IFF_MULTICAST)
#ifdef MCAST_PPP_BUG
&& !(ifp->int_if_flags & IFF_POINTOPOINT)
#endif
&& !(ifp->int_state & IS_ALIAS)) {
m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP);
m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT)
? ifp->int_dstaddr
: ifp->int_addr);
if (setsockopt(rip_sock,IPPROTO_IP, IP_ADD_MEMBERSHIP,
&m, sizeof(m)) < 0)
LOGERR("setsockopt(IP_ADD_MEMBERSHIP RIP)");
}
}
/* Prepare socket used for RIP.
*/
void
rip_on(struct interface *ifp)
{
/* If the main RIP socket is already alive, only start receiving
* multicasts for this interface.
*/
if (rip_sock >= 0) {
if (ifp != 0)
rip_mcast_on(ifp);
return;
}
/* If the main RIP socket is off, and it makes sense to turn it on,
* turn it on for all of the interfaces.
*/
if (rip_interfaces > 0 && !rdisc_ok) {
trace_act("turn on RIP\n");
/* Close all of the query sockets so that we can open
* the main socket. SO_REUSEPORT is not a solution,
* since that would let two daemons bind to the broadcast
* socket.
*/
for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
if (ifp->int_rip_sock >= 0) {
(void)close(ifp->int_rip_sock);
ifp->int_rip_sock = -1;
}
}
rip_sock = get_rip_sock(INADDR_ANY, 1);
rip_sock_mcast = 0;
/* Do not advertise anything until we have heard something
*/
if (next_bcast.tv_sec < now.tv_sec+MIN_WAITTIME)
next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME;
for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
if (!IS_RIP_IN_OFF(ifp->int_state))
ifp->int_state &= ~IS_RIP_QUERIED;
rip_mcast_on(ifp);
}
ifinit_timer.tv_sec = now.tv_sec;
fix_select();
} else if (ifp != 0
&& ifp->int_rip_sock < 0
&& !(ifp->int_state & IS_ALIAS)) {
/* RIP is off, so ensure there are sockets on which
* to listen for queries.
*/
ifp->int_rip_sock = get_rip_sock(ifp->int_addr, 0);
fix_select();
}
}
/* die if malloc(3) fails
*/
void *
rtmalloc(size_t size,
char *msg)
{
void *p = malloc(size);
if (p == 0)
logbad(1,"malloc() failed in %s", msg);
return p;
}
/* get a random instant in an interval
*/
void
intvl_random(struct timeval *tp, /* put value here */
u_long lo, /* value is after this second */
u_long hi) /* and before this */
{
tp->tv_sec = (time_t)(hi == lo
? lo
: (lo + arc4random() % ((1 + hi - lo))));
tp->tv_usec = arc4random() % 1000000;
}
void
timevaladd(struct timeval *t1,
struct timeval *t2)
{
t1->tv_sec += t2->tv_sec;
if ((t1->tv_usec += t2->tv_usec) > 1000000) {
t1->tv_sec++;
t1->tv_usec -= 1000000;
}
}
/* t1 = t2 - t3
*/
static void
timevalsub(struct timeval *t1,
struct timeval *t2,
struct timeval *t3)
{
t1->tv_sec = t2->tv_sec - t3->tv_sec;
if ((t1->tv_usec = t2->tv_usec - t3->tv_usec) < 0) {
t1->tv_sec--;
t1->tv_usec += 1000000;
}
}
void
msglog(char *p, ...)
{
va_list args;
trace_flush();
va_start(args, p);
vsyslog(LOG_ERR, p, args);
va_end(args);
if (ftrace != 0) {
if (ftrace == stdout)
(void)fputs("routed: ", ftrace);
va_start(args, p);
(void)vfprintf(ftrace, p, args);
va_end(args);
(void)fputc('\n', ftrace);
}
}
void
logbad(int dump, char *p, ...)
{
va_list args;
trace_flush();
va_start(args, p);
vsyslog(LOG_ERR, p, args);
va_end(args);
(void)fputs("routed: ", stderr);
va_start(args, p);
(void)vfprintf(stderr, p, args);
va_end(args);
(void)fputs("; giving up\n",stderr);
(void)fflush(stderr);
if (dump)
abort();
exit(1);
}
cscope나 ctags를 vi와
cscope나 ctags를 vi와 병행하시거나 emacs 를 쓰시면 보기 편합니다.
그걸 대뜸
그걸 대뜸 분석해보라는건 어떻게 해볼지 신입사원을 테스트해보는 겁니다. (신입이 아니시라면 죄송)
우선은 소스를 분석하는 방법을 대강 생각해 보셔야겠죠. 윗분이 얘기해 주신 툴들을 사용하면 좋습니다. 윈도에 익숙하시다면
소스를 윈도에 복사해서 sourceinsight를 이용해서 보는 방법도 있죠.
실행도 해보시고, 매뉴얼을 보시면서 기능을 익혀보시고, 소스를 조금 바꿔서 실행도 해보세요.
네트웍 관련 프로그램이니까, 네트웍 관련 명령어들도 익히지 않으면 안되겠네요.
그렇게 하다보면 어느새 리눅스 명령들에도 익숙해지고 개발툴에도 익숙해질겁니다.
여기다 소스를 붙여놓는다고 도와드릴 수가 없습니다. 그건 본인이 해야할 일이니까요. 상사에게 자신의 문제해결 능력을 보이는게 좋겠죠? 처음해본다고 불평만 한다면 발전이 있을 수 없습니다.
메뉴얼 있으시면 좀 보내주세여~~
플리즈TT
혹시 네프 과제;
구글에서 검색 되네요;;; ㅋ
이거 숙제에요 ㅋㅋ
헤더파일에도 선언 안되있는 변수들도 너무 많고..
난생 첨보는 함수들도 많고.. 이론은 아는데 소스는 몰겄네 ㅡ_ㅡ; 에혀 미치겄당
참고로 명령어 옵션 설명은 여기 가면 되어있음 ㅋㅋ
http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?cmd=getdoc&coll=0650&db=man&fname=1%20routed
명령어 옵션설명만 대충 적고 그 아래 하나도 모름 ㅋㅋ
플로우 챠트는 또 어케하냐 ㅡㅜ
ㅋㅋ이거 우리과 숙제 같네~-ㅇ-
아마 화요일까지죠?ㅋㅋ
숙제네요 ㅋㅋ
저도 지금 하는중.. 아~ 그냥 손놓고 싶다 ㅠㅜ
댓글 달기