/*******************************************************************************/
/* */
/* Copyright 2004 Pascal Gloor */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
/* You may obtain a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* */
/*******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <time.h>
#include <p_defs.h>
#include <p_dump.h>
/* opening file */
void p_dump_open_file(struct peer_t *peer, int id, uint32_t ts)
{
struct tm *tm;
struct in_addr addr;
struct stat sb;
char dirname[1024];
char filename[1024];
char mytime[100];
peer[id].filets = ts - ( ts % DUMPINTERVAL );
addr.s_addr = peer[id].ip;
tm = gmtime((time_t*)&peer[id].filets);
strftime(mytime, sizeof(mytime), "%Y%m%d%H%M%S" , tm);
snprintf(dirname, sizeof(dirname), "%s/%s", DUMPDIR, inet_ntoa(addr));
snprintf(peer[id].filename, sizeof(peer[id].filename), "%s/%s/%s", DUMPDIR, inet_ntoa(addr), mytime);
snprintf(filename, sizeof(filename), "%s/%s/%s", DUMPDIR, inet_ntoa(addr), "temp.dump");
#ifdef DEBUG
printf("opening '%s'\n",peer[id].filename);
#endif
if ( stat(dirname, &sb) == -1 )
{
mkdir(dirname, 0755);
}
/*
peer[id].fh = fopen(peer[id].filename, "wb" );
*/
peer[id].fh = fopen(filename, "wb" );
peer[id].empty = 1;
}
/* log keepalive msg */
void p_dump_add_keepalive(struct peer_t *peer, int id, uint32_t ts)
{
p_dump_check_file(peer,id,ts);
if ( peer[id].fh == NULL ) { return; }
peer[id].empty = 0;
{
struct dump_msg msg;
msg.type = htons(DUMP_KEEPALIVE);
msg.ts = htonl(ts);
msg.len = 0;
fwrite(&msg, sizeof(msg), 1, peer[id].fh);
}
}
/* log session close */
void p_dump_add_close(struct peer_t *peer, int id, uint32_t ts)
{
if ( peer[id].fh == NULL ) { return; }
peer[id].empty = 0;
{
struct dump_msg msg;
msg.type = htons(DUMP_CLOSE);
msg.ts = htonl(ts);
msg.len = 0;
fwrite(&msg, sizeof(msg), 1, peer[id].fh);
}
p_dump_check_file(peer,id,ts);
}
/* log session open */
void p_dump_add_open(struct peer_t *peer, int id, uint32_t ts)
{
p_dump_check_file(peer,id,ts);
if ( peer[id].fh == NULL ) { return; }
peer[id].empty = 0;
{
struct dump_msg msg;
msg.type = htons(DUMP_OPEN);
msg.ts = htonl(ts);
msg.len = 0;
fwrite(&msg, sizeof(msg), 1, peer[id].fh);
}
}
/* footer for each EOF */
void p_dump_add_footer(struct peer_t *peer, int id, uint32_t ts)
{
if ( peer[id].fh == NULL ) { return; }
{
struct dump_msg msg;
msg.type = htons(DUMP_FOOTER);
msg.ts = htonl(ts);
msg.len = 0;
fwrite(&msg, sizeof(msg), 1, peer[id].fh);
}
}
/* log bgp withdrawn msg */
void p_dump_add_withdrawn(struct peer_t *peer, int id, uint32_t ts, uint32_t prefix, uint8_t mask)
{
p_dump_check_file(peer,id,ts);
if ( peer[id].fh == NULL ) { return; }
peer[id].empty = 0;
{
struct dump_msg msg;
struct dump_withdrawn withdrawn;
msg.type = htons(DUMP_WITHDRAWN);
msg.ts = htonl(ts);
withdrawn.mask = mask;
if ( mask == 0 )
{
prefix = 0;
}
else
{
prefix &= ( 0xffffffff ^ ( ( 1 << ( 32 - mask ) ) - 1 ) );
}
withdrawn.prefix = htonl(prefix);
msg.len = htons(sizeof(withdrawn));
fwrite(&msg, sizeof(msg), 1, peer[id].fh);
fwrite(&withdrawn, sizeof(withdrawn), 1, peer[id].fh);
}
}
/* log bgp announce msg */
void p_dump_add_announce(struct peer_t *peer, int id, uint32_t ts,
uint32_t prefix, uint8_t mask,
void *aspath, uint16_t aspathlen,
void *community, uint16_t communitylen )
{
p_dump_check_file(peer,id,ts);
if ( peer[id].fh == NULL ) { return; }
peer[id].empty = 0;
{
struct dump_msg msg;
struct dump_announce announce;
struct dump_announce_aspath opt_aspath;
struct dump_announce_community opt_community;
msg.type = htons(DUMP_ANNOUNCE);
msg.ts = htonl(ts);
announce.mask = mask;
if ( mask == 0 )
{
prefix = 0;
}
else
{
prefix &= ( 0xffffffff ^ ( ( 1 << ( 32 - mask ) ) - 1 ) );
}
announce.prefix = htonl(prefix);
#ifdef DEBUG
{
struct in_addr addr;
addr.s_addr = htonl(prefix);
printf("DUMP ANNOUNCE %s/%u\n",inet_ntoa(addr),announce.mask);
}
#endif
opt_aspath.code = DUMP_OPT_ASPATH;
opt_aspath.len = htons(aspathlen * 2);
opt_community.code = DUMP_OPT_COMMUNITY;
opt_community.len = htons(communitylen * 4);
msg.len = htons( (communitylen*4) + (aspathlen*2) + sizeof(announce) + 6 );
memcpy(opt_aspath.data, aspath, aspathlen*2);
memcpy(opt_community.data, community, communitylen*4);
fwrite(&msg, sizeof(msg), 1, peer[id].fh);
fwrite(&announce, sizeof(announce), 1, peer[id].fh);
fwrite(&opt_aspath, (aspathlen*2) + 3, 1, peer[id].fh);
fwrite(&opt_community, (communitylen*4) + 3, 1, peer[id].fh);
}
}
/* check if need to reopen a new file */
void p_dump_check_file(struct peer_t *peer, int id, uint32_t ts)
{
uint32_t mts = ts - ( ts % DUMPINTERVAL );
if ( mts == peer[id].filets && peer[id].fh != NULL ) { return; }
if ( mts != peer[id].filets )
{
if ( peer[id].fh != NULL )
{
p_dump_add_footer(peer,id,ts);
p_dump_close_file(peer,id);
}
if ( peer[id].status != 0 )
{
p_dump_open_file(peer,id,ts);
p_dump_add_header(peer,id,ts);
}
}
else if ( peer[id].fh == NULL && peer[id].status != 0)
{
p_dump_open_file(peer,id,ts);
p_dump_add_header(peer,id,ts);
}
}
/* file header */
void p_dump_add_header(struct peer_t *peer, int id, uint32_t ts)
{
if ( peer[id].fh == NULL ) { return; }
{
struct dump_msg msg;
struct dump_header header;
msg.type = htons(DUMP_HEADER);
msg.ts = htonl(ts);
msg.len = htons(sizeof(header));
header.ip = peer[id].ip;
header.as = htons(peer[id].as);
fwrite(&msg, sizeof(msg), 1, peer[id].fh);
fwrite(&header, sizeof(header), 1, peer[id].fh);
}
}
/* close file */
void p_dump_close_file(struct peer_t *peer, int id)
{
char filename[1024];
struct in_addr addr;
if ( peer[id].fh == NULL ) { return; }
fclose(peer[id].fh);
addr.s_addr = peer[id].ip;
snprintf(filename, sizeof(filename), "%s/%s/%s", DUMPDIR, inet_ntoa(addr), "temp.dump");
rename(filename, peer[id].filename);
if ( peer[id].empty == 1 )
{
unlink(peer[id].filename);
}
}