NMS using ucd snmp

flatony의 이미지

ucd snmp api / command를 이용해서 일정 주기마다

등록된 agent에 폴링해서 MIB값을 가져오는 엔진을 만들생각입니다.

그런데 처음부터 막히네요

제작 환경은 linux 7.3 gcc 3.1.1 이구요 language는 C 로 구현할 거구요

등록된 agent의 ip를 확인한후 ping을 날려서 장비가 살아있는지

죽어있는지 확인한다음에 snmp 명령을 사용해서 MIB값을 가져와야할것같은데

프로그램 내부에서 ping명령을 사용해서 값을 가져온후에 내부에서

time이 3000ms 이상이거나 timeout이면 장비가 죽었다 판단하고

제대로 온다면 살아있다고 판단하게 하려고 하는데

system()함수를 썼더니 컴파일한후 쉘상태에서 실행되더라구요

결과값을 내부에서 받아서 time부분의 결과를 처리해야하는데,,,

음,,,,좀 장황하죠 ^^;;;

암튼,,,,쉘상태에서 쓰이는 프로그램을 제가 만드는 프로그램내에서 실행시킨후

값을 파싱하는 방법이 있는지 궁금합니다...

당최 어떻게 해야하는지 실마리 조차 풀수가 없으니 답답하기 그지없습니다.

고수님들께서 도움을 주시면 감사하겠습니다. ^^

pynoos의 이미지

외부프로그램을 써야만한다면....

1.
system 을 쓰지 마시고,
pipe, fork, dup2, exec 순서로 자프로세스의 표준 출력을 pipe로 받아 볼 수 있는 방법.

2.
system 을 쓸 때, 모든 출력을 특정 파일로 redirect 한 뒤 그 file을 읽는 방ㅂ법.

쉬운것으로 하셔요..

3. ping source를 가져다가 쓰는 것도.. 좋은 방법일지도 ..

hekimian의 이미지

저의 경우에는 router에 ping을 날리고 살아있는 것들에 대해서만 snmp와 cli 명령으로 데이타를 수집하는 프로그램을 개발한 적이 있는데...
(물론 CLI command는 router에 telnet으로 들어가서....)

ping 프로그램을 만들어 썼습니다. 가능하면 만들어 보심이...

ping 프로그램 설명은 stevens 아저씨의 unp 1권 Raw Socket chapter를 보시면 될거 같구요... 물론 다른 곳에도 많겠지만...

나를 죽이지 않는 모든 것은 나를 강하게 할 뿐이다.

cjy1126의 이미지

저도 같은 프로젝트하는데 ^^

#include "ping.h"

char send_buf[1500];			//보내는 버퍼
char recv_buf[1500];			//받는 버퍼
int g_id = 0;					//getpid()값 저장. 내가 보낸 ping만 받기위해
struct sockaddr_in dest_addr;	//목적지 소켓구조체
struct sockaddr_in src_addr;	//내 소켓구조체
pthread_t p_thread[2];			//쓰레드 id, [0]번 send, [1]번 recv

unsigned short icmp_cksum(u_short *addr, int len)		//ip체크섬 무시 -_-;
{
	register int nleft = len;
	register u_short *w = addr;
	register int sum = 0;
	u_short answer = 0;

	while(nleft>1){
		sum += *w++;
		nleft -= 2;
	}

	if(nleft==1){
		*(u_char *)(&answer) = *(u_char *)w;
		sum == answer;
	}

	sum = (sum>>16) + (sum&0xffff);
	sum += (sum>>16);
	answer = ~sum;
	return(answer);
}

void sig_alrm()			//ping 보내기를 마친지 sleep(x)초 후에 호출됨
{
	pthread_detach(p_thread[1]);		//[1](recv) 쓰레드를 죽인다
}

int init()		//ping 전체모듈을 준비하는 부분
{
	int i;
	connect_db();		//db 연결

	g_id = getpid();	//내가 보낸 ping을 확인하기위해 getpid() 저장
	init_ping_node();	//ping_node 생성
	get_addr();			//db에서 ip를 읽어오는 부분

	for(i=0; i<9; i++)
		insert_ping_node(ipaddr[i]);	//읽어온 ip 저장

	signal(SIGALRM, &sig_alrm);			//signal 선언

	memset(&dest_addr, 0, sizeof(struct sockaddr_in));		//목적지 구조체 초기화

	dest_addr.sin_family = AF_INET;
	dest_addr.sin_port = 0;

	return 0;
}

void init_ping_node(void)		//ping 노드 초기화하는 부분
{
	ping_head = (PING_NODE *)malloc(sizeof(PING_NODE));
	ping_tail = (PING_NODE *)malloc(sizeof(PING_NODE));
	ping_head->next = ping_tail;
	ping_head->prev = ping_head;
	ping_tail->next = ping_tail;
	ping_tail->prev = ping_head;
}

PING_NODE *insert_ping_node(char str[])		//새로운 노드 삽입
{
	PING_NODE *s;

	s = (PING_NODE *)malloc(sizeof(PING_NODE));

	strcpy(s->addr, str);		//str로 넘어온놈 ip에 저장
	s->check = 'N';				//기본 셋팅 N

	//새로운 노드는 가장 뒤에 붙인다.
	ping_tail->prev->next = s;
	s->prev = ping_tail->prev;
	s->next = ping_tail;
	ping_tail->prev = s;

	return s;
}

void *send_ping(void *arg)		//ping 보내는 쓰레드, 인자값으로 보내는 소켓을 받는다
{
	struct icmphdr *icmp;
	int sockfd = *((int *)arg);		//보내는 소켓을 sockfd에 저장
	static int g_seq = 0;			//icmp 시퀀스 넘버
	PING_NODE *s;

	for(s=ping_head->next; s!=ping_tail; s=s->next)		//head 다음부터 tail전까지 모든 ip에 핑을 보낸다
	{
		icmp = (struct icmphdr *)send_buf;
		icmp->type = ICMP_ECHO;
		icmp->code = 0;
		icmp->un.echo.id = g_id;				//내 pid
		icmp->un.echo.sequence = g_seq++;
		icmp->checksum = 0;
		icmp->checksum = icmp_cksum((unsigned short *)icmp, 16);		//체크섬

		dest_addr.sin_addr.s_addr = inet_addr(s->addr);			//목적지 ip가 계속 바뀐다
		if(sendto(sockfd, send_buf, 16, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr))<=0)
			perror("sendto: ");
	}

	sleep(1);		//ping를 다 send 한후 1초 기다린다
	sig_alrm();		//signal 호출
}

void recv_icmp(char *buf, int totlen)	//받은 ping 을 처리하는 부분
{
	int iplen, icmplen;
	struct iphdr *ip;
	struct icmphdr *icmp;
	int count=0;
	PING_NODE *s;

	s=ping_head->next;

	ip = (struct iphdr *)buf;
	iplen = ip->ihl*4;
	icmp = (struct icmphdr *)(buf + iplen);

	if(icmp->type == ICMP_ECHOREPLY){	//ping에 대한 reply 인가?
		if(icmp->un.echo.id == g_id)	//identified가 내 pid와 같은가?
		{
			for(count=0; count<icmp->un.echo.sequence; count++)	//시퀀스만큼 이동
				s=s->next;
			
			if(s!=ping_tail)	//찾은 부분이 끝이 아니면 check를 Y로 체크해서 살아있다고 표시
				s->check = 'Y';
		}
	}
}

void *recv_ping(void *arg)		//ping을 받는 쓰레드, 인자값으로 받는 소켓을 받는다
{
	int len, sz;
	int sockfd = *((int *)arg);	//받는 소켓을 sockfd에 저장

	memset(recv_buf, '\0', sizeof(recv_buf));

	while(1)
	{
		if((recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&src_addr, &len))<=0)
			perror("recvfrom: ");

		recv_icmp(recv_buf, sz);		//받은 데이터를 처리부분에 넘긴다
	}
}

int ping(void)
{
	int thr_id;
	int status;
	int sendfd, recvfd;
	
	if((sendfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP))<0){		//ping을 보내는 소켓을 만든다
		fprintf(stderr, "ERROR: Opening raw socket. (need UID 0)\n");
		exit(0);
	}

	if((recvfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP))<0){		//ping을 받는 소켓을 만든다
		fprintf(stderr, "ERROR: Opening raw socket. (need UID 0)\n");
		exit(0);
	}	

	init();			//전체 준비부분 실행

	thr_id = pthread_create(&p_thread[0], NULL, send_ping, (void *)&sendfd);		//ping을 보내는 쓰레드 실행
	thr_id = pthread_create(&p_thread[1], NULL, recv_ping, (void *)&recvfd);		//ping을 받는 쓰레드 실행

	//ping을 보내는 쓰레드의 종료를 처리 (detach로 죽이기 때문에 처리 안됨)
	pthread_join(p_thread[0], (void *)&status);
	pthread_join(p_thread[1], (void *)&status);		//ping을 받는 쓰레드의 종요를 처리(detach로 죽이기때문에 안됨 -_-;

}

몇군데 문제점이 있습니다.

일단 여러개 가져다가 고쳐쓰다보니 signal도 의미가 없어지고 -_-;

pthread_detach(p_thread[1]) 가 쓰레드 죽이는건줄 알았는데... 죽던말던 신경 안쓴다는거라네요.

즉 p_thread[1]은 계속 receive에서 블록되있습니다.

지금까지는 문제가 없어서... 제가 갑자기 UI로 옮겨가서 놔둔상태이지만, 발표회때 문제생기면 ㅡㅡㅋ

flatony의 이미지

덕분에 조금 실마리가 풀린거 같습니다.......

지금은 ping source 분석중이구요,,,

snmpget, snmpwalk, snmpd, snmp_api.h 분석을 마쳤구요,,,,

궁금한거 있음 또 올릴게염 ^.,^

모두모두 즐프하세여~~~~~

글고 cjy1126님 함께해여,,,ㅋㅋㅋ ^_____^;;;

hi!! nice to meet you!

thanks~!

jemiro의 이미지

ping정도는 직접 작성하시는것이 작성하는 프로그램이 제대로 돌아가는
첫번째 요건이라고 봅니다.

님께서 질문하신 방법의 젤 쉬운 방법이야.

FILE *fp;
char  buf[1024];

fp = popen("ping 127.0.0.1", "r");

while (fgets(buf, fp)) {
    printf("%s\n", buf);
}
pclose(fp);

위 예제에서 printf 부분만 수정하셔도 될듯 하지만,
popen을 모르시는 분들이 의외로 계시는군요. ^^;

P.S. cjy1126, flatony 두분혹시 같이 프로젝트 하시는거 아니에요? :)

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.