/**************************************************
OpengateM - MAC address authentication system 
 module to get mac address

Copyright (C) 2011 Opengate Project Team
Written by Yoshiaki Watanabe

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

Email: watanaby@is.saga-u.ac.jp
**************************************************/

#include	"opengatemmng.h"

/***************************************/
/* arp form is reformed to arp form    */ 
/* mac addr by arp 00:01:12:0b:..      */
/* mac addr by ndp 0:1:12:b:..         */
/* these are formated to 00:01:12:0b:..*/
/***************************************/
int reFormatMacAddr(char* macAddr)
{
  int m1,m2,m3,m4,m5,m6;
  if(sscanf(macAddr, "%x:%x:%x:%x:%x:%x", &m1,&m2,&m3,&m4,&m5,&m6)!=6) return FALSE;
  snprintf(macAddr, ADDRMAXLN,"%02x:%02x:%02x:%02x:%02x:%02x", m1,m2,m3,m4,m5,m6);
  return TRUE;
}

/************************************************************************/
/* get MAC address from ndp entry for clientAddr (nnnn:nnnn::nnnn:nnnn) */
/*  result is stored in queue                                           */
/************************************************************************/
int getMacAddrListFromNdp(char* interface){
  FILE *fpipe;
  char buf[BUFFMAXLN];
  char* firstTokenP;
  char* secondTokenP;
  char* thirdTokenP;
  char macAddr[ADDRMAXLN];
  char* p;
  char ifStr[WORDMAXLN];
  char* ndpPath=NULL;

  /* if interface is null, error return */
  if(isNull(interface)){
    err_msg("ERR at %s#%d: NIC device name is not set",__FILE__,__LINE__);
    return -1;
  }

  /* exec NDP 'ndp -a' , output to pipe */
  if(isNull(ndpPath=GetConfValue("NdpPath"))){
    err_msg("ERR at %s#%d:ndp path is not set in conf",__FILE__,__LINE__);
    return -1;
  }
  if((fpipe=Popenl(1, "r", ndpPath,"-a",(char *)0)) == NULL){ 
    err_msg("ERR at %s#%d: exec ndp -na error",__FILE__,__LINE__);
    return -1;
  }

  /*** get ndp response from pipe */
  /* skip first title line */
  if(fgets(buf, BUFFMAXLN, fpipe)==NULL){
    err_msg("ERR at %s#%d: readin error",__FILE__,__LINE__);
    Pclose(fpipe);
    return -1;
  }
  
  /* get MAC address from arp response             */
  /* arp response takes following format           */
  /* "[IPv6 Addr] [Mac] [InterfaceID] [Expire] [Status] [Flags] [Prbs]" */
  while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){

    firstTokenP = strtok(buf," "); /* first token */
    secondTokenP = strtok(NULL," "); /* second token */
    thirdTokenP = strtok(NULL," "); /* third token */

    /* skip if invalid address */
    if(strstr(secondTokenP, ":")==NULL)continue;

    /* if other interface, skip */
    if(strstr(thirdTokenP, interface)==NULL) continue;

    /* remove interface description(%fxp1) from the following form */
    /* 'fe80::202:b3ff:fe0a:c30e%fxp1' */
    snprintf(ifStr, WORDMAXLN, "%%%s", interface);
    if((p=strstr(firstTokenP, ifStr))!=NULL) *p='\0';

    /* Convert to ARP format */
    strlcpy(macAddr, secondTokenP, ADDRMAXLN);
    ReFormatMacAddr(macAddr);

    /* Insert to queue */
    /* initializing queue Initqueue() is needed previously */
    Enqueue(macAddr, firstTokenP);
  }

  Pclose(fpipe);
  
  return 0;
}

/*******************************************************************/
/* get MAC address for clientAddr (nnn.nnn.nnn.nnn) by arp request */
/*  result is stored in queue                                      */
/*******************************************************************/
int getMacAddrListFromArp(char* interface){
  char buf[BUFFMAXLN];
  char *startp;
  char *endp;
  FILE *fpipe;
  char* macAddr;
  char* ipAddr;
  char options[WORDMAXLN];
  char* arpPath=NULL;

  /* if null, error return */
  if(isNull(interface)){
    err_msg("ERR at %s#%d: NIC device name is not set",__FILE__,__LINE__);
    return -1;
  }

  /* set arp options */
  snprintf(options, WORDMAXLN, "-a -i %s", interface);

  /* exec arp 'arp -a -i fxp1', output to pipe */
  if(isNull(arpPath=GetConfValue("ArpPath"))){
    err_msg("ERR at %s#%d: arp path is not set in conf",__FILE__,__LINE__);
    return -1;
  }
  if( (fpipe=Popenl(1, "r", arpPath, options, (char *)0)) == NULL){ 
    err_msg("ERR at %s#%d: exec arp error",__FILE__,__LINE__);
    return -1;
  }
  
  /* get arp response from pipe */  
  while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){

    /* arp response takes following format            */
    /* "? (133.49.22.1) at 8:0:20:a5:4:62 [ethernet]" */
    /* get ip address from above string               */
    if((startp=strstr(buf," ("))==NULL) continue;
    startp=startp+2;
    if((endp=strstr(startp, ") "))==NULL) continue;
    
    /* save as ip address and cut off string at endp */
    *endp='\0';
    ipAddr=startp;
    
    /* get MAC address from above string             */
    if((startp=strstr(endp+1," at "))==NULL) continue;
    startp=startp+4;
    if((endp=strstr(startp, " "))==NULL) continue;
    
    /* save as mac address and cut off string at endp */
    *endp='\0';
    macAddr=startp;
    
    /* skip if invalid address */
    if((strstr(macAddr, ":"))==NULL) continue;
    
    /* save to queue */
    /* initializing queue Initqueue() is needed previously */
    Enqueue(macAddr, ipAddr);
  }
    
  /* close pipe */
  Pclose(fpipe);
    
  return 0;
}


/****************************************/
/****************************************/
int GetMacAddrListFromArp(char* interface)
{
  int ret;
  if(debug>1) err_msg("DEBUG:=>getMacAddrListFromArp(%s)", interface);
  ret=getMacAddrListFromArp(interface);
  if(debug>1) err_msg("DEBUG:(%d)<=getMacAddrListFromArp( )",ret);

  return ret;
}  

int GetMacAddrListFromNdp(char* interface){
  int ret;
  if(debug>1) err_msg("DEBUG:=>getMacAddrListFromNdp(%s)", interface);
  ret=getMacAddrListFromNdp(interface);
  if(debug>1) err_msg("DEBUG:(%d)<=getMacAddrListFromNdp( )",ret);

  return ret;
}

int ReFormatMacAddr(char* macAddr){
  int ret;
  if(debug>1) err_msg("DEBUG:=>reFormatMacAddr(%s)", macAddr);
  ret=reFormatMacAddr(macAddr);
  if(debug>1) err_msg("DEBUG:(%d)<=reFormatMacAddr(%s)", ret, macAddr);
  return ret;
}

