|  | @@ -1236,6 +1236,33 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
 | 
	
		
			
				|  |  |    return 0; /* unreached but keeps the compiler happy */
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#ifdef TRANS_PF
 | 
	
		
			
				|  |  | +static int pf_socket = -1;
 | 
	
		
			
				|  |  | +static int
 | 
	
		
			
				|  |  | +get_pf_socket(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  int pf;
 | 
	
		
			
				|  |  | +  /*  Ideally, this should be opened before dropping privs. */
 | 
	
		
			
				|  |  | +  if (pf_socket >= 0)
 | 
	
		
			
				|  |  | +    return pf_socket;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#ifdef OPENBSD
 | 
	
		
			
				|  |  | +  /* only works on OpenBSD */
 | 
	
		
			
				|  |  | +  pf = open("/dev/pf", O_RDONLY);
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +  /* works on NetBSD and FreeBSD */
 | 
	
		
			
				|  |  | +  pf = open("/dev/pf", O_RDWR);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (pf < 0) {
 | 
	
		
			
				|  |  | +    log_warn(LD_NET, "open(\"/dev/pf\") failed: %s", strerror(errno));
 | 
	
		
			
				|  |  | +    return -1;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  pf_socket = pf;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /** Fetch the original destination address and port from a
 | 
	
		
			
				|  |  |   * system-specific interface and put them into a
 | 
	
		
			
				|  |  |   * socks_request_t as if they came from a socks request.
 | 
	
	
		
			
				|  | @@ -1287,29 +1314,15 @@ connection_ap_get_original_destination(edge_connection_t *conn,
 | 
	
		
			
				|  |  |    pnl.sport           = htons(conn->_base.port);
 | 
	
		
			
				|  |  |    pnl.daddr.v4.s_addr = proxy_addr.sin_addr.s_addr;
 | 
	
		
			
				|  |  |    pnl.dport           = proxy_addr.sin_port;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* XXX We should open the /dev/pf device once and close it at cleanup time
 | 
	
		
			
				|  |  | -   * instead of reopening it for every connection. Ideally, it should be
 | 
	
		
			
				|  |  | -   * opened before dropping privs. */
 | 
	
		
			
				|  |  | -#ifdef OPENBSD
 | 
	
		
			
				|  |  | -  /* only works on OpenBSD */
 | 
	
		
			
				|  |  | -  pf = open("/dev/pf", O_RDONLY);
 | 
	
		
			
				|  |  | -#else
 | 
	
		
			
				|  |  | -  /* works on NetBSD and FreeBSD */
 | 
	
		
			
				|  |  | -  pf = open("/dev/pf", O_RDWR);
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (pf < 0) {
 | 
	
		
			
				|  |  | -    log_warn(LD_NET, "open(\"/dev/pf\") failed: %s", strerror(errno));
 | 
	
		
			
				|  |  | +  
 | 
	
		
			
				|  |  | +  pf = get_pf_socket();
 | 
	
		
			
				|  |  | +  if (pf<0)
 | 
	
		
			
				|  |  |      return -1;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (ioctl(pf, DIOCNATLOOK, &pnl) < 0) {
 | 
	
		
			
				|  |  |      log_warn(LD_NET, "ioctl(DIOCNATLOOK) failed: %s", strerror(errno));
 | 
	
		
			
				|  |  | -    close(pf);
 | 
	
		
			
				|  |  |      return -1;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  close(pf);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    tor_inet_ntoa(&pnl.rdaddr.v4, tmpbuf, sizeof(tmpbuf));
 | 
	
		
			
				|  |  |    strlcpy(req->address, tmpbuf, sizeof(req->address));
 |