#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <arpa/inet.h>

#include <err.h>
#include <stdio.h>


/*
 * p - pointer within ipopt_list structure.
 * q - pointer within ls/ss rr route data
 * r - pointer to hbuf
 *
 * Format of output is (connection was from site a through b through c to d):
 *
 *	loose:      @site-c@site-b:site-a
 *	strict:	   !@site-c@site-b:site-a
 */

char *decodeipsr(int fd, char hbuf[], int buflen) {

  struct ipoption ipopt;
  int ipoptlen, j;
  char *p, *q, *r;
  struct in_addr addr;
  struct sockaddr_in sa;
  int salen;
  
  hbuf[0]=0; r=hbuf+1;
  if (getpeername(fd, (struct sockaddr*)&sa, (salen=sizeof(sa), &salen)) < 0)
    warn("[getpeername]");
  if (sa.sin_family == AF_INET) {
    if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, (char*)&ipopt,
		   (ipoptlen=sizeof(ipopt), &ipoptlen)) < 0)
      warn("decodeipsr [getsockopt]");
    if (ipoptlen != 0) {

      p=(char*)&ipopt.ipopt_list;
      while (p != NULL && (p < (char*)&ipopt+ipoptlen))
	switch (*p) {
	case (char)IPOPT_EOL: 
	  p=NULL; continue; 
	case (char)IPOPT_NOP:
	  p++; continue;
	case (char)IPOPT_SSRR:
	case (char)IPOPT_LSRR:
/*	  r = &hbuf[strlen(hbuf)]; */
	  r += sprintf(r, "%s@%s",
		       (*p == (char)IPOPT_SSRR)?"!":"",
		       inet_ntoa(ipopt.ipopt_dst));
	  j = (*++p)/sizeof(struct in_addr) -1;	/* p is now length */
	  q = p+2;      /* q skips length and router pointer to data */
	  for ( ; j>=0 ; j--) {
	    memcpy(&addr, q, sizeof(addr));
	    r += sprintf(r, "%c%s", j?'@':':', inet_ntoa(addr));
	    q+=sizeof(struct in_addr); 
	  }
	  p+=*p;
	  continue;
	default:
	  p+=*(p+1); /* Increment by option length */
	  continue;
	}
      return hbuf;
    } else {
      return inet_ntoa(sa.sin_addr);
    }
  } else {
    return NULL;
  }
}


void main(int argc, char *argv[]) {
  char hbuf[100];

 printf("Got back [%s].\n", decodeipsr(0, hbuf, sizeof(hbuf)));
}

