home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
sustworks.com
/
2014.06.sustworks.com.tar
/
sustworks.com
/
open_source_IPNetRouter_TNKE.dmg
/
IPNetRouter_TNKE.h
< prev
next >
Wrap
C/C++ Source or Header
|
2005-08-27
|
12KB
|
311 lines
//
// IPNetRouter_TNKE.h
// Mac OS X Interface Filter NKE
//
// Created by psichel [PAS] on Teus Nov 12 2002.
// Copyright (c) 2002 Sustainable Softworks Inc. All rights reserved.
//
// Per Apple Computer's Open Source license, IPNetRouter_TNKE.c is
// Open Source to be available from the sustworks website.
// Other source files used by this kernel extension to perform
// NAT or IP filtering need not be Open Source.
//
// Design Overview
// ===============
// [Some of this information will change for Tiger versus Panther, but concepts remain the same.]
//
// As an Interface (or Protocol) Filter NKE, we have two basic tasks:
//
// (1) Insert our NKE as a non-global socket filter so it can
// intercept socket operations to serve as a control channel
// to any companion applications.
//
// (2) Insert our NKE between the IP protocol layer and the DLIL
// so it can examine and modify IP traffic on each data link.
//
// I have chosen to use standard UDP for the control channel interface
// since most control operations are either periodic reports (traffic
// counts, filter log entries) or transaction oriented (configure some
// internal state). For just logging traffic, I might have used TCP.
// For driver control operations, I might have used a PF_NDRV raw
// socket (requires privileges).
//
// Alternatively we can use PF_NKE as defined by Apple for our control
// interface, but Im not sure what value PF_NKE provides [PAS].
//
// Since our NKE is non-global, a controller establishes communication by:
// (1) Making sure the NKE is loaded (kextload corresponding file)
// (2) Opening a UDP socket
// (3) Performing a setsockopt specifying our NKE by handle (signature)
//
// setsockopt(s, SOL_SOCKET, SO_NKE, &so_nke, sizeof(struct so_nke));
//
// See "Inside Mac OS X: Network Kernel Extensions" (file NKE.pdf)
// page 20-21.
//
// Notice this NKE is designed to monitor more than one data link
// at a time (DLIL attachment instance), and allow multiple controllers.
// We define per DLIL attachment storage, and global storage allowing
// our controllers to interract with a single data link, or the entire
// set of data links.
//
// For inserting our NKE below IP as a protocol filter, we use dlil_find_dltag
// to get the dl_tag for the protocol attachment to a given interface.
// If dlil_find_dltag returns an error, the protocol has not been attached
// to that data link so is not available.
//
// For insertering our NKE below IP as an interface filter, we use the ifnet
// global variable which points to the list of ifnet structures and scan the
// list to find the desired ifnet structure with matching interface name.
//
// The dlil_pr_flt_str (dlil_if_flt_str) used to register filters has a cookie
// field that will be passed to our data link functions. We set the cookie to
// point to the instance storage we created for this dlil attachment allowing
// us to quickly identify which data link instance was called and collect
// per data link statistics.
//
// Once a controller has connected to our NKE, it can specify which dlil
// attachment is of interest for data link operations. This will cause
// the NKE to attach to the corresponding data link if needed, or add
// a reference if we're already attached.
//
// When the number of references for a dlil attachment reaches zero,
// the NKE is detached from that protocol interface pair or interface.
// We must also detach all references when the kext is unloaded
// and notify any clients their socket is going away.
// [Not sure how to do this yet except marking the socket invalid so
// the next request will fail - PAS]
// Notice the kernel will close any open sockets when a process terminates,
// so we intercept the soclose to tear down any dlil attach instances
// associated with that controlling socket.
//
// Since our NKE can have multiple controllers from different applications,
// normally it should remain loaded, unless the user explicitly wishes
// to unload for some reason (debugging, or to load a newer version).
// We provide a menu item in the companion application to do this.
// Since there is no way to predict when another controller might try to
// insert the NKE after verifying it is loaded, it is the users responsibility
// to stop any applications that rely on this NKE before trying to unload it.
// Controllers should be designed to fail gracefully if the NKE goes away.
// One possibility is to ask the NKE if there are any outstanding connections
// before unloading it and/or tell the NKE to tear down any such connections.
//
//
// Control Channel Access
// ----------------------
//
// Once a control socket has inserted our NKE, the following socket
// operations access NKE functions as follows:
//
// connect -> ipk_connect
// disconnect -> ipk_disconnect
// ! close is intercepted to call our ipk_disconnect
// soclose -> ipk_disconnect
// soconnect -> ipk_connect
// setsockopt -> ik_control
// recvfrom -> any data inserted in socket buffer
// sendto -> appends data to socket buffer
//
// Most controller initiated operations should use setsockopt since it
// allows passing an arbitrary structure and returning a result.
// These structures and option codes are defined below.
//
// Both solicited and unsolicited NKE data or reports can be read
// using recvfrom (standard UDP). The report datagrams need to be self
// identifying and optionally tied to the corresponding request.
//
// We use the dl_tag as a convenient
// shorthand to uniquely identify each dlil attach instance.
//
#include <sys/types.h>
#include "ipkTypes.h"
// use IPNetRouter app signature 'IPnl'
#define IPNetRouter_TNKE_Handle 0x49506E6C
//
// UDP SOL_SOCKET level options for controlling our NKE
// Usage: setsockopt(s, SOL_SOCKET, optionCode, &so_nke, sizeof(struct so_nke));
// s should be a UDP (or PF_NKE) socket with our NKE previously inserted using the SO_NKE option
#define SO_ATTACH_LINK 0x10A0
#define SO_DETACH_LINK 0x10A1
#define SO_MONITOR_ON 0x10A2
#define SO_MONITOR_OFF 0x10A3
#define SO_FILTER_DOWNLOAD 0x10A4
#define SO_FILTER_UPLOAD 0x10A5
#define SO_KFT_RESET 0X10A6
#define SO_FILTER_COUNT 0X10A7
#define SO_SET_TIME 0x10A8
#define SO_DROP_RESPONSE 0x10A9
#define SO_TRIGGER_DURATION 0X10AA
#define SO_TRIGGER_ADDRESS 0X10AB
#define SO_TRIGGER_UPLOAD 0X10AC
#define SO_INTERFACE_UPLOAD 0X10AD
#define SO_PORTMAP_UPLOAD 0x10AE
#define SO_IPK_MESSAGE 0X10AF
#define SO_NAT_UPLOAD 0x10B0
#define SO_TRIGGER_COUNT 0X10B1
#define SO_INTERFACE_COUNT 0X10B2
#define SO_PORTMAP_COUNT 0X10B3
#define SO_SET_FLAGS 0x10B4
#define SO_GET_FLAGS 0x10B5
typedef struct sopt_attachParam {
char bsdName[16]; // bsdName of desired interface
short protocolFilter; // 0=interface filter, 1=protocol filter
} sopt_attachParam_t;
typedef struct sopt_timeParam {
u_long timeStamp; // seconds from gettimeofday()
int secondOfDay;
int day;
} sopt_timeParam_t;
typedef struct sopt_flagsParam {
u_int32_t flags; // desired values
u_int32_t mask; // which bits to modify
} sopt_flagsParam_t;
#define kFlag_sourceAwareRouting 0x01
typedef KFT_interfaceEntry_t sopt_kftParameters_t;
// buffer size for ipk messages (must fit within a 2048 byte cluster)
#define kUpdateBufferSize 2000
// ---------------------------------------------------------------------------------
// generic upstream message
// ---------------------------------------------------------------------------------
typedef struct ipk_message {
int32_t length; // length of message
int32_t type; // identify message type/version
} ipk_message_t;
// ---------------------------------------------------------------------------------
// upstream message for monitorStats
// ---------------------------------------------------------------------------------
typedef struct ipk_monitorStats {
int32_t length; // length of message
int32_t type; // identify message type/version
int32_t sendCount;
int32_t receiveCount;
} ipk_monitorStats_t;
// ---------------------------------------------------------------------------------
// upstream message for filter logging
// ---------------------------------------------------------------------------------
typedef struct ipk_filterLog {
int32_t length; // length of message
int32_t type; // identify message type/version
unsigned char text[500]; // text of log message
} ipk_filterLog_t;
// ---------------------------------------------------------------------------------
// upstream message for filter update
// ---------------------------------------------------------------------------------
typedef struct ipk_countUpdate {
int32_t index;
int64_t lastTime;
KFT_stat64_t match;
KFT_stat64_t byte;
} ipk_countUpdate_t;
typedef struct ipk_filterUpdate {
int32_t length; // length of message
int32_t type; // identify message type/version
ipk_countUpdate_t countUpdate[1]; // some number of count updates
} ipk_filterUpdate_t;
// ---------------------------------------------------------------------------------
// upstream message for trigger update
// ---------------------------------------------------------------------------------
typedef struct ipk_triggerUpdate {
int32_t length; // length of message
int32_t type; // identify message type/version
KFT_triggerEntry_t triggerUpdate[1]; // some number of trigger updates
} ipk_triggerUpdate_t;
// ---------------------------------------------------------------------------------
// upstream message for interface update
// ---------------------------------------------------------------------------------
typedef struct ipk_interfaceUpdate {
int32_t length; // length of message
int32_t type; // identify message type/version
KFT_interfaceEntry_t interfaceUpdate[1]; // some number of interface updates
} ipk_interfaceUpdate_t;
// ---------------------------------------------------------------------------------
// upstream message for connection update
// ---------------------------------------------------------------------------------
typedef struct ipk_connectionUpdate {
int32_t length; // length of message
int32_t type; // identify message type/version
KFT_connectionEntry_t connectionUpdate[1]; // some number of connection updates
} ipk_connectionUpdate_t;
// ---------------------------------------------------------------------------------
// upstream message for nat update
// ---------------------------------------------------------------------------------
typedef struct ipk_natUpdate {
int32_t length; // length of message
int32_t type; // identify message type/version
KFT_natEntry_t natUpdate[1]; // some number of nat updates
} ipk_natUpdate_t;
// ---------------------------------------------------------------------------------
// upstream message for bridge update
// ---------------------------------------------------------------------------------
typedef struct ipk_bridgeUpdate {
int32_t length; // length of message
int32_t type; // identify message type/version
KFT_bridgeEntry_t bridgeUpdate[1]; // some number of connection updates
} ipk_bridgeUpdate_t;
// ---------------------------------------------------------------------------------
// upstream message for failover update
// ---------------------------------------------------------------------------------
typedef struct ipk_failoverUpdate {
int32_t length; // length of message
int32_t type; // identify message type/version
int32_t request; // failover dest, remove dest, failover default route
u_int32_t dstAddress; // dest ip of datagram to be re-routed
char bsdName[kBSDNameLength];
} ipk_failoverUpdate_t;
#define kFailoverDestination 1
#define kFailoverRemove 2
#define kFailoverDefault1 3
#define kFailoverDefault2 4
// Message types
#define KFT_filterEntry_size 400
#define kMonitorStats 1
#define kFilterLog 2
#define kFilterUpdate 3
#define kFilterAlert 4
#define kFilterEmail 5
#define kFilterURL 6
#define kFilterAppleScript 7
#define kTriggerUpdate 8
#define kConnectionUpdate 9
#define kNatUpdate 10
#define kInterfaceUpdate 11
#define kPortMapUpdate 12
#define kBridgeUpdate 13
#define kFailoverUpdate 14
void PROJECT_sendMessageToAll(ipk_message_t *message);
int PROJECT_modifyReadyPacket(KFT_packetData_t* packet);
void PROJECT_lock();
void PROJECT_unlock();
// tag values
#define TAG_IN 1
#define TAG_OUT 2
errno_t PROJECT_mtag(mbuf_t mbuf_ref, int tag_value);
int PROJECT_is_mtag(mbuf_t mbuf_ref, int tag_value);