├── menubar ├── t2 │ ├── menubar-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── Status-user-busy-icon.imageset │ │ │ ├── Status-user-busy-icon.png │ │ │ └── Contents.json │ │ ├── Status-user-online-icon.imageset │ │ │ ├── Status-user-online-icon.png │ │ │ └── Contents.json │ │ ├── Status-user-offline-icon.imageset │ │ │ ├── Status-user-offline-icon.png │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── cstuff.h │ ├── TSClipView.swift │ ├── AppDelegate.swift │ ├── Base.lproj │ │ └── MainMenu.xib │ ├── Info.plist │ ├── SettingsWindow.swift │ ├── CHelper.swift │ ├── TSTextField.swift │ ├── Socket.swift │ ├── IpFilter.swift │ ├── Interface.swift │ ├── MyMenu.swift │ ├── IpViewController.swift │ ├── SocketViewController.swift │ └── InterfaceViewController.swift ├── menubar.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── project.pbxproj ├── t2Tests │ ├── Info.plist │ └── t2Tests.swift └── t2UITests │ ├── Info.plist │ └── t2UITests.swift ├── kext ├── kext.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── project.pbxproj ├── iffilter │ ├── errors.h │ ├── Info.plist │ ├── common.h │ ├── ip_filter.h │ ├── socket_filter.h │ ├── socket_filter.c │ ├── interface_filter.h │ ├── ip_filter.c │ ├── netfil.c │ └── interface_filter.c ├── README.md └── c examples │ └── interface_list.c ├── netfil.xcworkspace └── contents.xcworkspacedata ├── reload.sh ├── LICENSE.md ├── DISCLAIMER.md ├── .gitignore └── README.md /menubar/t2/menubar-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "cstuff.h" 2 | #include 3 | -------------------------------------------------------------------------------- /menubar/t2/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /menubar/t2/Assets.xcassets/Status-user-busy-icon.imageset/Status-user-busy-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsacyber/netfil/HEAD/menubar/t2/Assets.xcassets/Status-user-busy-icon.imageset/Status-user-busy-icon.png -------------------------------------------------------------------------------- /menubar/t2/cstuff.h: -------------------------------------------------------------------------------- 1 | #ifndef cstuff_h 2 | #define cstuff_h 3 | 4 | struct CCArray { 5 | int size; 6 | void **values; 7 | }; 8 | 9 | typedef struct CCArray CCArray; 10 | 11 | #endif /* cstuff_h */ 12 | -------------------------------------------------------------------------------- /menubar/t2/Assets.xcassets/Status-user-online-icon.imageset/Status-user-online-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsacyber/netfil/HEAD/menubar/t2/Assets.xcassets/Status-user-online-icon.imageset/Status-user-online-icon.png -------------------------------------------------------------------------------- /menubar/t2/Assets.xcassets/Status-user-offline-icon.imageset/Status-user-offline-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsacyber/netfil/HEAD/menubar/t2/Assets.xcassets/Status-user-offline-icon.imageset/Status-user-offline-icon.png -------------------------------------------------------------------------------- /menubar/t2/TSClipView.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import AppKit 3 | 4 | class TSClipView : NSClipView { 5 | override var isFlipped: Bool { 6 | get { 7 | return true 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /kext/kext.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /menubar/menubar.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /netfil.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /reload.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | if [ $# -lt 2 ]; then 4 | echo $0 \ \ 5 | exit 1 6 | fi 7 | 8 | FILE=$1 9 | NAME=$2 10 | 11 | sudo kextunload -b ${NAME} || echo $NAME not loaded 12 | sudo rm -rf ${NAME}.kext 13 | cp -R ${FILE} ./${NAME}.kext 14 | sudo chown -R root:wheel ${NAME}.kext 15 | sudo kextutil --verbose ${NAME}.kext -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | This Work was prepared by a United States Government employee and, therefore, is excluded from copyright by Section 105 of the Copyright Act of 1976. 2 | 3 | Copyright and Related Rights in the Work worldwide are waived through the [CC0 1.0](https://creativecommons.org/publicdomain/zero/1.0/) [Universal license](https://creativecommons.org/publicdomain/zero/1.0/legalcode). 4 | -------------------------------------------------------------------------------- /kext/iffilter/errors.h: -------------------------------------------------------------------------------- 1 | #ifndef errors_h 2 | #define errors_h 3 | 4 | #define CLEANUP_INTERFACE = 8 5 | #define CLEANUP_SOCKET = 9 6 | #define CLEANUP_IP = 10 7 | 8 | #define START_INTERFACE = 11 9 | #define START_SOCKET = 12 10 | #define START_IP = 13 11 | 12 | #define STOP_INTERFACE = START_INTERFACE 13 | #define STOP_SOCKET = START_SOCKET 14 | #define STOP_IP = START_IP 15 | 16 | 17 | #endif /* errors_h */ 18 | -------------------------------------------------------------------------------- /menubar/t2/Assets.xcassets/Status-user-busy-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Status-user-busy-icon.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /menubar/t2/Assets.xcassets/Status-user-offline-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Status-user-offline-icon.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /menubar/t2/Assets.xcassets/Status-user-online-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Status-user-online-icon.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /menubar/t2Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /menubar/t2UITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /menubar/t2Tests/t2Tests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import t2 3 | 4 | class t2Tests: XCTestCase { 5 | 6 | override func setUp() { 7 | super.setUp() 8 | // Put setup code here. This method is called before the invocation of each test method in the class. 9 | } 10 | 11 | override func tearDown() { 12 | // Put teardown code here. This method is called after the invocation of each test method in the class. 13 | super.tearDown() 14 | } 15 | 16 | func testExample() { 17 | // This is an example of a functional test case. 18 | // Use XCTAssert and related functions to verify your tests produce the correct results. 19 | } 20 | 21 | func testPerformanceExample() { 22 | // This is an example of a performance test case. 23 | self.measure { 24 | // Put the code you want to measure the time of here. 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /menubar/t2/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Cocoa 3 | 4 | @NSApplicationMain 5 | class AppDelegate: NSObject, NSApplicationDelegate { 6 | 7 | @IBOutlet weak var window: NSWindow! 8 | let statusItem = NSStatusBar.system().statusItem(withLength: NSVariableStatusItemLength) 9 | 10 | func applicationDidFinishLaunching(_ aNotification: Notification) { 11 | // Insert code here to initialize your application 12 | 13 | self.statusItem.title = "netfil" 14 | self.statusItem.menu = MyMenu() 15 | 16 | // print(Interface.isActive, Interface.ioByte, Interface.iByte, Interface.oByte) 17 | // Interface.list = ["what"] 18 | // print(Interface.list) 19 | 20 | IpFilter.shared.addr = "127.0.0.1" 21 | print("is set to...", IpFilter.shared.addr) 22 | } 23 | 24 | func applicationWillTerminate(_ aNotification: Notification) { 25 | // Insert code here to tear down your application 26 | } 27 | 28 | 29 | } 30 | 31 | -------------------------------------------------------------------------------- /kext/iffilter/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | KEXT 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | NSHumanReadableCopyright 22 | Copyright © 2017. All rights reserved. 23 | OSBundleLibraries 24 | 25 | com.apple.kpi.bsd 26 | 11.2 27 | com.apple.kpi.libkern 28 | 11.2 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /menubar/t2/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /menubar/t2/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | LSUIElement 26 | 27 | NSHumanReadableCopyright 28 | Copyright © 2017. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /menubar/t2/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /menubar/t2UITests/t2UITests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | class t2UITests: XCTestCase { 4 | 5 | override func setUp() { 6 | super.setUp() 7 | 8 | // Put setup code here. This method is called before the invocation of each test method in the class. 9 | 10 | // In UI tests it is usually best to stop immediately when a failure occurs. 11 | continueAfterFailure = false 12 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 13 | XCUIApplication().launch() 14 | 15 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | super.tearDown() 21 | } 22 | 23 | func testExample() { 24 | // Use recording to get started writing UI tests. 25 | // Use XCTAssert and related functions to verify your tests produce the correct results. 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /kext/README.md: -------------------------------------------------------------------------------- 1 | To load the kext, use the `reload.sh` file in the root directoy of this workspace. This will unload the kext if present, give the new kext the proper permissions, then load it. 2 | 3 | Interface Filter Single interface example 4 | 5 | // start a fitler 6 | 7 | struct iff_filter filter; 8 | 9 | filter.iff_cookie = 0; 10 | filter.iff_name = "iffilter"; 11 | filter.iff_output = out_handler; 12 | filter.iff_input = in_handler; 13 | filter.iff_protocol = 0; 14 | filter.iff_event = event_handler; 15 | filter.iff_ioctl = ioctl_handler; 16 | filter.iff_detached = NULL; 17 | 18 | errno_t err = ifnet_find_by_name("en4", &p_ifnet); 19 | if (err) { 20 | printf("interface en4 not found\n"); 21 | return KERN_SUCCESS; 22 | } 23 | 24 | iflt_attach(p_ifnet, &filter, &filter_ref); 25 | 26 | // stop the filter 27 | 28 | if(p_ifnet != NULL) { 29 | ifnet_release(p_ifnet); 30 | } 31 | if(filter_ref != NULL) { 32 | iflt_detach(filter_ref); 33 | } 34 | 35 | The interface list is taken from userspace in an "array" structure 36 | 37 | struct array { 38 | int size; 39 | void **values; 40 | }; 41 | 42 | the `size` is the number of null-terminated strings stored in values with a max length of `MAXCOMLEN`. See an example in the C example folder. 43 | 44 | The ip addr sysctl takes an in_addr or an in6_addr. -------------------------------------------------------------------------------- /kext/iffilter/common.h: -------------------------------------------------------------------------------- 1 | #ifndef common_h 2 | #define common_h 3 | 4 | // https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/reference/reference.html#//apple_ref/doc/uid/TP40001858-CH232-SW1 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include // includes functions for manipulating mbuf data structures. These are used heavily for passing packets and packet fragments around throughout the protocol stack. 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include // includes functions for manipulating network interfaces, including packet injection, attaching/detaching protocols, attaching/detaching interfaces, and so on. 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "errors.h" 27 | 28 | struct array { 29 | int size; 30 | void **values; 31 | }; 32 | 33 | extern OSMallocTag globalOSMallocTag; 34 | 35 | #if defined(DEBUG) && DEBUG > 0 36 | #define DPRINT(fmt, args...) printf("DEBUG: %s:%d:%s(): " fmt, \ 37 | __FILE__, __LINE__, __func__, ##args) 38 | #else 39 | #define DPRINT(fmt, args...) /* Don't do anything in release builds */ 40 | #endif 41 | 42 | #endif /* common_h */ 43 | -------------------------------------------------------------------------------- /menubar/t2/SettingsWindow.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import AppKit 3 | 4 | let PADDING : CGFloat = 15 5 | 6 | class SettingsWindow : NSWindow { 7 | 8 | } 9 | 10 | class SettingsViewController : NSViewController { 11 | 12 | override func loadView() { 13 | view = NSTabView() 14 | view.frame.size.width = 500 15 | //self.preferredContentSize = (view as! NSTabView).minimumSize 16 | //(view as! NSStackView).orientation = NSUserInterfaceLayoutOrientation.vertical 17 | //(view as! NSStackView).spacing = CGFloat(PADDING) 18 | //let titleBarSize = NSWindow.frameRect(forContentRect: self.view.frame, styleMask: NSWindowStyleMask.titled).height 19 | //(view as! NSStackView).edgeInsets = EdgeInsets(top: titleBarSize + CGFloat(PADDING), left: PADDING, bottom: PADDING, right: PADDING) 20 | } 21 | 22 | override func viewDidLoad() { 23 | super.viewDidLoad() 24 | 25 | let one = NSTabViewItem(viewController: InterfaceViewController()) 26 | one.label = "Interface Filter" 27 | (view as! NSTabView).addTabViewItem(one) 28 | 29 | let two = NSTabViewItem(viewController: SocketViewController()) 30 | two.label = "Socket Filter" 31 | (view as! NSTabView).addTabViewItem(two) 32 | 33 | let three = NSTabViewItem(viewController: IpViewController()) 34 | three.label = "IP Filter" 35 | (view as! NSTabView).addTabViewItem(three) 36 | 37 | //(view as! NSStackView).addArrangedSubview(t) 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /menubar/t2/CHelper.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension String { 4 | /** Creates an `UnsafeMutableBufferPointer` that must be freed properly after use */ 5 | public var UTF8CStringBuffer : UnsafeMutableBufferPointer { 6 | get { 7 | let bufferSize = self.characters.count + 1 8 | let buffer = UnsafeMutableBufferPointer(start: UnsafeMutablePointer.allocate(capacity: bufferSize), count: bufferSize) 9 | 10 | self.utf8CString.withUnsafeBufferPointer { 11 | for (index, character) in $0.enumerated() { 12 | buffer[index] = character 13 | } 14 | } 15 | 16 | buffer[bufferSize - 1] = 0 // null terminate 17 | 18 | return buffer 19 | } 20 | } 21 | } 22 | 23 | extension CCArray { 24 | public mutating func initialize(from collection: C) where C.Iterator.Element == String, C.IndexDistance == Int { 25 | let count = collection.count 26 | 27 | let buffer = UnsafeMutableBufferPointer(start: UnsafeMutablePointer.allocate(capacity: count * MemoryLayout.size), count: count) 28 | 29 | for (index, element) in collection.enumerated() { 30 | buffer[index] = element.UTF8CStringBuffer.baseAddress.map({ .init($0) }) 31 | } 32 | 33 | self.size = Int32(count) 34 | self.values = buffer.baseAddress 35 | } 36 | 37 | public func deallocate() { 38 | for element in UnsafeMutableBufferPointer(start: self.values, count: Int(self.size)) { 39 | free(element) 40 | } 41 | 42 | free(self.values) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /DISCLAIMER.md: -------------------------------------------------------------------------------- 1 | ## Disclaimer of Warranty 2 | This Work is provided "as is." Any express or implied warranties, including but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the United States Government be liable for any direct, indirect, incidental, special, exemplary or consequential damages (including, but not limited to, procurement of substitute goods or services, loss of use, data or profits, or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this Guidance, even if advised of the possibility of such damage. 3 | 4 | The User of this Work agrees to hold harmless and indemnify the United States Government, its agents and employees from every claim or liability (whether in tort or in contract), including attorneys' fees, court costs, and expenses, arising in direct consequence of Recipient's use of the item, including, but not limited to, claims or liabilities made for injury to or death of personnel of User or third parties, damage to or destruction of property of User or third parties, and infringement or other violations of intellectual property or technical data rights. 5 | 6 | Nothing in this Work is intended to constitute an endorsement, explicit or implied, by the United States Government of any particular manufacturer's product or service. 7 | 8 | ## Disclaimer of Endorsement 9 | Reference herein to any specific commercial product, process, or service by trade name, trademark, manufacturer, or otherwise, in this Work does not constitute an endorsement, recommendation, or favoring by the United States Government and shall not be used for advertising or product endorsement purposes. 10 | -------------------------------------------------------------------------------- /kext/iffilter/ip_filter.h: -------------------------------------------------------------------------------- 1 | // https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/ip_filter_nke/ip_filter_nke.html#//apple_ref/doc/uid/TP40001858-CH229-SW1 2 | 3 | #ifndef ip_filter_h 4 | #define ip_filter_h 5 | 6 | #include "common.h" 7 | #include // includes functions for attaching a packet filter for IPv4 or IPv6 packets. These functions are appropriate for a KEXT that filters IP traffic. 8 | #include 9 | #include 10 | 11 | extern int ip_status; 12 | 13 | /** 14 | * input output byte limit for interface filter 15 | * 16 | * 0 is unlimted or no limit (default) 17 | **/ 18 | extern int user_ip_io_byte_limit; 19 | /** 20 | * input byte limit for interface filter 21 | * 22 | * 0 is unlimted or no limit (default) 23 | **/ 24 | extern int user_ip_in_byte_limit; 25 | /** 26 | * output byte limit for interface filter 27 | * 28 | * 0 is unlimted or no limit (default) 29 | **/ 30 | extern int user_ip_out_byte_limit; 31 | 32 | /** 33 | * initial setup for the ip filter 34 | * @return 0 on success 35 | **/ 36 | kern_return_t ip_filter_setup(); 37 | 38 | /** 39 | * final cleanup for the ip filter 40 | * @return 0 on success 41 | **/ 42 | kern_return_t ip_filter_cleanup(); 43 | 44 | /** 45 | * must call ip_filter_stop before exiting 46 | * @result 0 on success, error otherwise 47 | **/ 48 | errno_t ip_filter_start(); 49 | 50 | /** 51 | * @result 0 on success, error otherwise 52 | **/ 53 | errno_t ip_filter_stop(); 54 | 55 | /** 56 | * status of filtering for ip 57 | * can be used to start or stop the interface filter 58 | * or see if the filter is currently active 59 | * 60 | *takes an integer as an argument 61 | * @param oidp id 62 | * @param arg1 first argument 63 | * @param arg2 second argument 64 | * @param req the request 65 | **/ 66 | int sysctl_ip_status_handler SYSCTL_HANDLER_ARGS; 67 | 68 | /** 69 | * `in_addr` or `in6_addr` for the ip filter 70 | * @param oidp id 71 | * @param arg1 first argument 72 | * @param arg2 second argument 73 | * @param req the request 74 | **/ 75 | int sysctl_ip_addr_handler SYSCTL_HANDLER_ARGS; 76 | 77 | #endif /* ip_filter_h */ 78 | -------------------------------------------------------------------------------- /menubar/t2/TSTextField.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import AppKit 3 | 4 | 5 | class TSTextFieldCell : NSTextFieldCell { 6 | 7 | var leftPadding : CGFloat = 0 8 | var rightPadding : CGFloat = 15 9 | 10 | convenience init(leftPadding : CGFloat, rightPadding : CGFloat) { 11 | self.init() 12 | self.leftPadding = leftPadding 13 | self.rightPadding = rightPadding 14 | } 15 | 16 | override func drawingRect(forBounds rect: NSRect) -> NSRect { 17 | var r = rect 18 | r.origin.x = r.origin.x + leftPadding 19 | r.size.width = r.size.width - leftPadding - rightPadding 20 | return super.drawingRect(forBounds: r) 21 | } 22 | } 23 | 24 | class TSTextField : NSTextField { 25 | 26 | var isEditing : Bool = false 27 | var segmentControl : NSSegmentedControl? 28 | var segmentControlIndex : Int = 1 29 | 30 | override func becomeFirstResponder() -> Bool { 31 | 32 | let orig = super.becomeFirstResponder() 33 | Swift.print("did come") 34 | if(orig) { 35 | self.isEditing = true 36 | if(segmentControl != nil) { 37 | if((segmentControl?.segmentCount)! > segmentControlIndex) { 38 | segmentControl?.setEnabled(true, forSegment: segmentControlIndex) 39 | } 40 | } 41 | } 42 | return orig 43 | } 44 | 45 | override func textDidEndEditing(_ notification: Notification) { 46 | Swift.print("did end") 47 | super.textDidEndEditing(notification) 48 | self.isEditing = false 49 | if(segmentControl != nil) { 50 | if((segmentControl?.segmentCount)! > segmentControlIndex) { 51 | segmentControl?.setEnabled(false, forSegment: segmentControlIndex) 52 | } 53 | } 54 | } 55 | 56 | override func selectText(_ sender: Any?) { 57 | super.selectText(sender) 58 | self.isEditing = true 59 | if(segmentControl != nil) { 60 | if((segmentControl?.segmentCount)! > segmentControlIndex) { 61 | segmentControl?.setEnabled(true, forSegment: segmentControlIndex) 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /kext/iffilter/socket_filter.h: -------------------------------------------------------------------------------- 1 | // https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/socket_nke/socket_nke.html#//apple_ref/doc/uid/TP40001858-CH228-SW1 2 | 3 | #ifndef socket_filter_h 4 | #define socket_filter_h 5 | 6 | #include "common.h" 7 | #include // includes functions and data type definitions for creating a socket filter. 8 | #include // includes functions for manipulating a socket, including packet send/receive and flag manipulation 9 | #include 10 | #include 11 | #include 12 | #include // includes functions for packet injection. It also includes functions to register “plumbers”—handlers that deal with requests for attaching a protocol to an interface (and detaching, and so on). 13 | 14 | extern int user_pid; 15 | 16 | extern int socket_status; 17 | 18 | /** 19 | * input output byte limit for socket filter 20 | * 21 | * 0 is unlimted or no limit (default) 22 | **/ 23 | extern int user_socket_io_byte_limit; 24 | /** 25 | * input byte limit for socket filter 26 | * 27 | * 0 is unlimted or no limit (default) 28 | **/ 29 | extern int user_socket_in_byte_limit; 30 | /** 31 | * output byte limit for socket filter 32 | * 33 | * 0 is unlimted or no limit (default) 34 | **/ 35 | extern int user_socket_out_byte_limit; 36 | 37 | /** 38 | * initial setup for the socket filter 39 | * @return 0 on success 40 | **/ 41 | kern_return_t socket_filter_setup(); 42 | 43 | /** 44 | * final cleanup for the socket filter 45 | * @return 0 on success 46 | **/ 47 | kern_return_t socket_filter_cleanup(); 48 | 49 | /** 50 | * must call socket_filter_stop before exiting 51 | * @result 0 on success, error otherwise 52 | **/ 53 | errno_t socket_filter_start(); 54 | 55 | /** 56 | * @result 0 on success, error otherwise 57 | **/ 58 | errno_t socket_filter_stop(); 59 | 60 | /** 61 | * status of filtering for sockets 62 | * can be used to start or stop the interface filter 63 | * or see if the filter is currently active 64 | * 65 | *takes an integer as an argument 66 | * @param oidp id 67 | * @param arg1 first argument 68 | * @param arg2 second argument 69 | * @param req the request 70 | **/ 71 | int sysctl_socket_status_handler SYSCTL_HANDLER_ARGS; 72 | 73 | #endif /* socket_filter_h */ 74 | -------------------------------------------------------------------------------- /kext/c examples/interface_list.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct array { 9 | int size; 10 | void **names; 11 | } array; 12 | 13 | int main(int argc, const char * argv[]) { 14 | // insert code here... 15 | printf("Hello, World!\n"); 16 | 17 | // Set the interface list to 'en4' 18 | 19 | char *name = "net.netfil.interface.list"; 20 | int retval = 0; 21 | struct array r; 22 | r.size = 1; 23 | char *test = "en4"; 24 | r.names = malloc(r.size * sizeof(char*)); 25 | r.names[0] = test; 26 | size_t len; 27 | len=sizeof(struct array); 28 | 29 | printf("%s %p %p\n", r.names[0], r.names[0], r.names); 30 | retval=sysctlbyname(name, NULL, NULL, &r, len); // set userInterface 31 | 32 | 33 | free(r.names); 34 | 35 | if(retval != 0) { 36 | printf("Unable to set the interface list\n"); 37 | return -1; 38 | } 39 | 40 | // Now lets confirm that our list was saved by getting the list from 41 | // the kernel 42 | 43 | 44 | len = sizeof(int); 45 | int size = -1; 46 | 47 | retval = sysctlbyname(name, &size, &len, NULL, 0); // get count 48 | 49 | if(retval != 0) { 50 | printf("Unable to get the size of the interface list\n"); 51 | return retval; 52 | } 53 | 54 | // now that we know how many items are in the list, let's get the 55 | // actual list that is in the kernel 56 | 57 | struct array r2; 58 | r2.size = size; 59 | r2.names = malloc(r2.size * sizeof(char *)); 60 | len = sizeof(struct array); 61 | for(int i = 0; i < r2.size; i++) { 62 | r2.names[i] = malloc(MAXCOMLEN); 63 | } 64 | 65 | retval=sysctlbyname(name, &r2, &len, NULL, 0); // get rar 66 | 67 | if(retval != 0) { 68 | printf("Unable to get the interface list\n"); 69 | } 70 | 71 | for(int i = 0; i < r2.size; i++) { 72 | free(r2.names[i]) 73 | } 74 | 75 | free(r2.names); 76 | 77 | #ifdef START_IT 78 | 79 | // you can set the byte limits, with zero being no-limit / unlimited 80 | 81 | int n = 0; 82 | retval = sysctlbyname("net.netfil.interface.ibyte", NULL, NULL, &n, sizeof(n)); 83 | 84 | n = 0; 85 | retval = sysctlbyname("net.netfil.interface.obyte", NULL, NULL, &n, sizeof(n)); 86 | 87 | n = 0; 88 | retval = sysctlbyname("net.netfil.interface.iobyte", NULL, NULL, &n, sizeof(n)); 89 | 90 | // then set the status to 1 to start the filter! 91 | 92 | n = 1; 93 | retval = sysctlbyname("net.netfil.interface.status", NULL, NULL, &n, sizeof(n)); 94 | 95 | if(retval != 0) { 96 | printf("Unable to start the interface filter\n"); 97 | } 98 | 99 | #endif 100 | 101 | return retval; 102 | } 103 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/macos,swift,c,xcode 3 | 4 | ### C ### 5 | # Prerequisites 6 | *.d 7 | 8 | # Object files 9 | *.o 10 | *.ko 11 | *.obj 12 | *.elf 13 | 14 | # Linker output 15 | *.ilk 16 | *.map 17 | *.exp 18 | 19 | # Precompiled Headers 20 | *.gch 21 | *.pch 22 | 23 | # Libraries 24 | *.lib 25 | *.a 26 | *.la 27 | *.lo 28 | 29 | # Shared objects (inc. Windows DLLs) 30 | *.dll 31 | *.so 32 | *.so.* 33 | *.dylib 34 | 35 | # Executables 36 | *.exe 37 | *.out 38 | *.app 39 | *.i*86 40 | *.x86_64 41 | *.hex 42 | 43 | # Debug files 44 | *.dSYM/ 45 | *.su 46 | *.idb 47 | *.pdb 48 | 49 | # Kernel Module Compile Results 50 | *.mod* 51 | *.cmd 52 | modules.order 53 | Module.symvers 54 | Mkfile.old 55 | dkms.conf 56 | 57 | ### macOS ### 58 | *.DS_Store 59 | .AppleDouble 60 | .LSOverride 61 | 62 | # Icon must end with two \r 63 | Icon 64 | 65 | 66 | # Thumbnails 67 | ._* 68 | 69 | # Files that might appear in the root of a volume 70 | .DocumentRevisions-V100 71 | .fseventsd 72 | .Spotlight-V100 73 | .TemporaryItems 74 | .Trashes 75 | .VolumeIcon.icns 76 | .com.apple.timemachine.donotpresent 77 | 78 | # Directories potentially created on remote AFP share 79 | .AppleDB 80 | .AppleDesktop 81 | Network Trash Folder 82 | Temporary Items 83 | .apdisk 84 | 85 | ### Swift ### 86 | # Xcode 87 | # 88 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 89 | 90 | ## Build generated 91 | build/ 92 | DerivedData/ 93 | 94 | ## Various settings 95 | *.pbxuser 96 | !default.pbxuser 97 | *.mode1v3 98 | !default.mode1v3 99 | *.mode2v3 100 | !default.mode2v3 101 | *.perspectivev3 102 | !default.perspectivev3 103 | xcuserdata/ 104 | 105 | ## Other 106 | *.moved-aside 107 | *.xccheckout 108 | *.xcscmblueprint 109 | 110 | ## Obj-C/Swift specific 111 | *.hmap 112 | *.ipa 113 | *.dSYM.zip 114 | *.dSYM 115 | 116 | ## Playgrounds 117 | timeline.xctimeline 118 | playground.xcworkspace 119 | 120 | # Swift Package Manager 121 | # 122 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 123 | # Packages/ 124 | # Package.pins 125 | .build/ 126 | 127 | # CocoaPods 128 | # 129 | # We recommend against adding the Pods directory to your .gitignore. However 130 | # you should judge for yourself, the pros and cons are mentioned at: 131 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 132 | # 133 | # Pods/ 134 | 135 | # Carthage 136 | # 137 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 138 | # Carthage/Checkouts 139 | 140 | Carthage/Build 141 | 142 | # fastlane 143 | # 144 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 145 | # screenshots whenever they are needed. 146 | # For more information about the recommended setup visit: 147 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 148 | 149 | fastlane/report.xml 150 | fastlane/Preview.html 151 | fastlane/screenshots 152 | fastlane/test_output 153 | 154 | ### Xcode ### 155 | # Xcode 156 | # 157 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 158 | 159 | ## Build generated 160 | 161 | ## Various settings 162 | 163 | ## Other 164 | 165 | # End of https://www.gitignore.io/api/macos,swift,c,xcode 166 | -------------------------------------------------------------------------------- /menubar/t2/Socket.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class Socket : NSObject { 4 | 5 | @objc 6 | enum activity : Int, CustomStringConvertible { 7 | case active 8 | case inactive 9 | case unknown 10 | 11 | var description : String { 12 | switch self { 13 | case .active: return "Active" 14 | case .inactive: return "Inactive" 15 | default: return "Unknown" 16 | } 17 | } 18 | } 19 | 20 | static var shared : Socket = Socket() 21 | 22 | override init() { 23 | super.init() 24 | } 25 | 26 | dynamic var isActive : activity { 27 | get { 28 | var value : CInt = -1; 29 | var size = -1; 30 | let ret = sysctlbyname("net.netfil.socket.status", &value, &size, nil, 0) 31 | print(ret, value, size) 32 | if(ret != 0) { return .unknown } 33 | return ret == 0 && value == 1 ? Socket.activity.active : Socket.activity.inactive 34 | } 35 | set { 36 | self.willChangeValue(forKey: "isActive") 37 | var nVal : CInt = newValue == Socket.activity.active ? 1 : 0 38 | let _ = sysctlbyname("net.netfil.socket.status", nil, nil, &nVal, MemoryLayout.size) 39 | self.didChangeValue(forKey: "isActive") 40 | } 41 | } 42 | 43 | var ioByte : CInt { 44 | get { 45 | var value : CInt = -2; 46 | var size = -3; 47 | let ret = sysctlbyname("net.netfil.socket.iobyte", &value, &size, nil, 0) 48 | return ret == 0 ? value : -1 49 | } 50 | set { 51 | var nVal : CInt = newValue 52 | var value : CInt = -2; 53 | var size = -3; 54 | let _ = sysctlbyname("net.netfil.socket.iobyte", &value, &size, &nVal, MemoryLayout.size) 55 | } 56 | } 57 | 58 | var iByte : CInt { 59 | get { 60 | var value : CInt = -2; 61 | var size = -3; 62 | let ret = sysctlbyname("net.netfil.socket.ibyte", &value, &size, nil, 0) 63 | return ret == 0 ? value : -1 64 | } 65 | set { 66 | var nVal : CInt = newValue 67 | var value : CInt = -2; 68 | var size = -3; 69 | let _ = sysctlbyname("net.netfil.socket.ibyte", &value, &size, &nVal, MemoryLayout.size) 70 | } 71 | } 72 | 73 | var oByte : CInt { 74 | get { 75 | var value : CInt = -2; 76 | var size = -3; 77 | let ret = sysctlbyname("net.netfil.socket.obyte", &value, &size, nil, 0) 78 | return ret == 0 ? value : -1 79 | } 80 | set { 81 | var nVal : CInt = newValue 82 | var value : CInt = -2; 83 | var size = -3; 84 | 85 | let _ = sysctlbyname("net.netfil.socket.obyte", &value, &size, &nVal, MemoryLayout.size) 86 | } 87 | } 88 | 89 | 90 | var pid : CInt { 91 | get { 92 | var value : CInt = -2; 93 | var size = -3; 94 | let ret = sysctlbyname("net.netfil.socket.pid", &value, &size, nil, 0) 95 | return ret == 0 ? value : -1 96 | } 97 | set { 98 | var nVal : CInt = newValue 99 | var value : CInt = -2; 100 | var size = -3; 101 | 102 | let _ = sysctlbyname("net.netfil.socket.pid", &value, &size, &nVal, MemoryLayout.size) 103 | } 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /menubar/t2/IpFilter.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Darwin 3 | 4 | class IpFilter : NSObject { 5 | 6 | @objc 7 | enum activity : Int, CustomStringConvertible { 8 | case active 9 | case inactive 10 | case unknown 11 | 12 | var description : String { 13 | switch self { 14 | case .active: return "Active" 15 | case .inactive: return "Inactive" 16 | default: return "Unknown" 17 | } 18 | } 19 | } 20 | 21 | static var shared : IpFilter = IpFilter() 22 | 23 | override init() { 24 | super.init() 25 | } 26 | 27 | dynamic var isActive : activity { 28 | get { 29 | var value : CInt = -1; 30 | var size = -1; 31 | let ret = sysctlbyname("net.netfil.ip.status", &value, &size, nil, 0) 32 | print(ret, value, size) 33 | if(ret != 0) { return .unknown } 34 | return ret == 0 && value == 1 ? IpFilter.activity.active : IpFilter.activity.inactive 35 | } 36 | set { 37 | 38 | self.willChangeValue(forKey: "isActive") 39 | var nVal : CInt = newValue == IpFilter.activity.active ? 1 : 0 40 | print("trying to set", nVal) 41 | let _ = sysctlbyname("net.netfil.ip.status", nil, nil, &nVal, MemoryLayout.size) 42 | self.didChangeValue(forKey: "isActive") 43 | } 44 | } 45 | 46 | var ioByte : CInt { 47 | get { 48 | var value : CInt = -2; 49 | var size = -3; 50 | let ret = sysctlbyname("net.netfil.ip.iobyte", &value, &size, nil, 0) 51 | return ret == 0 ? value : -1 52 | } 53 | set { 54 | var nVal : CInt = newValue 55 | var value : CInt = -2; 56 | var size = -3; 57 | let _ = sysctlbyname("net.netfil.ip.iobyte", &value, &size, &nVal, MemoryLayout.size) 58 | } 59 | } 60 | 61 | var iByte : CInt { 62 | get { 63 | var value : CInt = -2; 64 | var size = -3; 65 | let ret = sysctlbyname("net.netfil.ip.ibyte", &value, &size, nil, 0) 66 | return ret == 0 ? value : -1 67 | } 68 | set { 69 | var nVal : CInt = newValue 70 | var value : CInt = -2; 71 | var size = -3; 72 | let _ = sysctlbyname("net.netfil.ip.ibyte", &value, &size, &nVal, MemoryLayout.size) 73 | } 74 | } 75 | 76 | var oByte : CInt { 77 | get { 78 | var value : CInt = -2; 79 | var size = -3; 80 | let ret = sysctlbyname("net.netfil.ip.obyte", &value, &size, nil, 0) 81 | return ret == 0 ? value : -1 82 | } 83 | set { 84 | var nVal : CInt = newValue 85 | var value : CInt = -2; 86 | var size = -3; 87 | 88 | let _ = sysctlbyname("net.netfil.ip.obyte", &value, &size, &nVal, MemoryLayout.size) 89 | } 90 | } 91 | 92 | 93 | var addr : String { 94 | get { 95 | //let a = in_addr() 96 | //inet_addr() 97 | 98 | // TODO: this 99 | 100 | 101 | var a : in_addr_t = in_addr_t() 102 | var size = MemoryLayout.size(ofValue: a) 103 | let ret = sysctlbyname("net.netfil.ip.addr", &a, &size, nil, 0) 104 | 105 | if(ret == 0) { 106 | var ipAddressString = [CChar](repeating: 0, count:Int(INET_ADDRSTRLEN)) 107 | let _ = inet_ntop(AF_INET, &a, &ipAddressString, socklen_t(INET_ADDRSTRLEN)); 108 | return String(cString: ipAddressString) 109 | } 110 | 111 | return "" 112 | } 113 | set { 114 | print("set", newValue) 115 | 116 | var a = inet_addr(newValue.UTF8CStringBuffer.baseAddress) 117 | 118 | if a == __uint32_t.max { 119 | print("error") 120 | } 121 | 122 | 123 | let _ = sysctlbyname("net.netfil.ip.addr", nil, nil, &a, MemoryLayout.size(ofValue: a)) 124 | 125 | } 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # netfil 2 | 3 | This is a experimental beginner [Network Kernel Extention (NKE)](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/intro/intro.html) with a menu bar application. It can filter by process identifier, IP, or network interfaces using a i/o byte limit. 4 | 5 | This project is NOT meant to be run on a production machine - use at your own risk! Tested on macOS 10.12.1 6 | 7 | This is a kernel level alternative to [`netman`](https://github.com/iadgov/netman). 8 | 9 | The following NKE filters are used: 10 | * [Socket Filters](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/socket_nke/socket_nke.html) - Filter all sockets by process identitifier 11 | * [IP Filters](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/ip_filter_nke/ip_filter_nke.html#//apple_ref/doc/uid/TP40001858-CH229-SW1) - Filter IP traffic by address 12 | * [Interface Filters](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/interface_filter_nke/interface_filter_nke.html#//apple_ref/doc/uid/TP40001858-CH230-SW1) - Filter all traffic happening on specified interfaces 13 | 14 | ### Example use cases 15 | 16 | * Create a socket filter to ensure an application only uploads X bytes 17 | * Create an interface filter to ensure you don't go over your data limit when tethering 18 | * Create an IP filter to manage your bandwidth usage to an external host 19 | 20 | ## KEXT 21 | 22 | You can load the KEXT with the `./reload.sh iffilter.kext com.company.netfil` command. Note: Loading unsigned kernel extensions requires System Integrity Protection (SIP) to be turn off. 23 | 24 | ## System Controls 25 | 26 | This NKE uses sysctl to cross boundaries between kernel code and appliactions. 27 | 28 | You can communicate directly with them using the `sysctl` command. 29 | To view most system controls run `sysctl -a net.netfil` 30 | 31 | Interface Filter 32 | * `net.netfil.interface.list` ``: `size` is the number of interfaces; `names` contains a list of null-terminated network interface names. 33 | * `net.netfil.interface.ibyte` `` 34 | * `net.netfil.interface.obyte` `` 35 | * `net.netfil.interface.iobyte` `` 36 | * `net.netfil.interface.status` ``: `0` is "off", `1` is "on" 37 | 38 | Socket Filter 39 | * `net.netfil.socket.pid` `` 40 | * `net.netfil.socket.ibyte` `` 41 | * `net.netfil.socket.obyte` `` 42 | * `net.netfil.socket.iobyte` `` 43 | * `net.netfil.socket.status` ``: `0` is "off", `1` is "on" 44 | 45 | IP Filter 46 | * `net.netfil.ip.addr` `` or `` 47 | * `net.netfil.ip.ibyte` `` 48 | * `net.netfil.ip.obyte` `` 49 | * `net.netfil.ip.iobyte` `` 50 | * `net.netfil.ip.status` ``: `0` is "off", `1` is "on" 51 | 52 | Note: You cannot set the `net.netfil.ip.addr` or the `net.netfil.interface.list` via commandline. 53 | 54 | To run a fitler, first set its' options then change its' status to `1`. It is always smart to validate your options before you start. 55 | 56 | For `iobyte`, `ibyte`, and `obyte`, a zero value represents unmetered/unlimited (no filtering). 57 | 58 | ## Menu Bar / GUI Application 59 | 60 | You can use the menu bar application to control the KEXT. A green icon with a dot means the filter is "on", a red icon with a line means the filter is "off", a gray icon with a radar-like symobl means the KEXT is probably not loaded or there is an error. Icon are from Oxygen Team. 61 | 62 | ## Limitations 63 | 64 | ### KEXT 65 | 66 | * Right now you can only run one socket, interface, or IP filter at a time. 67 | * Does not add new interfaces to filter (mac policy might be able to help with this?) 68 | * Anyone can change the variables as root permission is not required. This is very dangerous! 69 | * Not signed so have to jump thru some hoops to get this loaded on your machine. 70 | 71 | ### GUI 72 | 73 | * Application will only filter IPv4 addresses for the IP filter. 74 | * Application will not be alerted instantly on KEXT changes. 75 | 76 | ## Useful Resources 77 | 78 | * https://github.com/gdbinit/tcplognke 79 | * https://github.com/ikob/i-Path 80 | * https://github.com/tesseract2048/netfat/ 81 | * https://github.com/applesrc/SharedIP/ 82 | * https://github.com/williamluke/peerguardian-linux 83 | * http://phrack.org/issues/69/7.html 84 | * http://soundly.me/discovering-source-folder-when-hiding-files-in-osx-kernel-rootkits/ 85 | * kernel debugging 86 | ** http://lightbulbone.com/2016/10/04/intro-to-macos-kernel-debugging.html 87 | * mac policies 88 | ** https://www.synack.com/2015/11/17/monitoring-process-creation-via-the-kernel-part-i/ 89 | ** https://developer.apple.com/reference/kernel/mpo_ifnet_label_associate_t?language=objc 90 | * Icons from the Oxygen Icon pack under the GNU Lesser General Public License 91 | 92 | ## License 93 | See [LICENSE](./LICENSE.md). 94 | 95 | ## Disclaimer 96 | See [DISCLAIMER](./DISCLAIMER.md). -------------------------------------------------------------------------------- /menubar/t2/Interface.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class Interface : NSObject { 4 | 5 | @objc 6 | enum activity : Int, CustomStringConvertible { 7 | case active 8 | case inactive 9 | case unknown 10 | 11 | var description : String { 12 | switch self { 13 | case .active: return "Active" 14 | case .inactive: return "Inactive" 15 | default: return "Unknown" 16 | } 17 | } 18 | } 19 | 20 | static var shared : Interface = Interface() 21 | 22 | override init() { 23 | super.init() 24 | } 25 | 26 | dynamic var isActive : activity { 27 | get { 28 | var value : CInt = -1; 29 | var size = -1; 30 | let ret = sysctlbyname("net.netfil.interface.status", &value, &size, nil, 0) 31 | print(ret, value, size) 32 | if(ret != 0) { return .unknown } 33 | return ret == 0 && value == 1 ? Interface.activity.active : Interface.activity.inactive 34 | } 35 | set { 36 | self.willChangeValue(forKey: "isActive") 37 | var nVal : CInt = newValue == Interface.activity.active ? 1 : 0 38 | let _ = sysctlbyname("net.netfil.interface.status", nil, nil, &nVal, MemoryLayout.size) 39 | self.didChangeValue(forKey: "isActive") 40 | } 41 | } 42 | 43 | var ioByte : CInt { 44 | get { 45 | var value : CInt = -2; 46 | var size = -3; 47 | let ret = sysctlbyname("net.netfil.interface.iobyte", &value, &size, nil, 0) 48 | return ret == 0 ? value : -1 49 | } 50 | set { 51 | var nVal : CInt = newValue 52 | var value : CInt = -2; 53 | var size = -3; 54 | let _ = sysctlbyname("net.netfil.interface.iobyte", &value, &size, &nVal, MemoryLayout.size) 55 | } 56 | } 57 | 58 | var iByte : CInt { 59 | get { 60 | var value : CInt = -2; 61 | var size = -3; 62 | let ret = sysctlbyname("net.netfil.interface.ibyte", &value, &size, nil, 0) 63 | return ret == 0 ? value : -1 64 | } 65 | set { 66 | var nVal : CInt = newValue 67 | var value : CInt = -2; 68 | var size = -3; 69 | let _ = sysctlbyname("net.netfil.interface.ibyte", &value, &size, &nVal, MemoryLayout.size) 70 | } 71 | } 72 | 73 | var oByte : CInt { 74 | get { 75 | var value : CInt = -2; 76 | var size = -3; 77 | let ret = sysctlbyname("net.netfil.interface.obyte", &value, &size, nil, 0) 78 | return ret == 0 ? value : -1 79 | } 80 | set { 81 | var nVal : CInt = newValue 82 | var value : CInt = -2; 83 | var size = -3; 84 | 85 | let _ = sysctlbyname("net.netfil.interface.obyte", &value, &size, &nVal, MemoryLayout.size) 86 | } 87 | } 88 | 89 | 90 | var list : [String] { 91 | get { 92 | var size = -3; 93 | var usize = 0; 94 | var ret = sysctlbyname("net.netfil.interface.list", &size, &usize, nil, 0) 95 | print(ret, size) 96 | if(ret != 0 || size <= 0) { 97 | return [String]() 98 | } 99 | 100 | var a = CCArray() 101 | a.size = Int32(size); 102 | 103 | let buffer = UnsafeMutableBufferPointer(start: UnsafeMutablePointer.allocate(capacity: Int(a.size) * MemoryLayout.size), count: Int(a.size)) 104 | 105 | for index in 0...size 113 | 114 | ret = sysctlbyname("net.netfil.interface.list", &a, &size, nil, 0) 115 | 116 | print(ret, a.size) 117 | 118 | var retRar = [String]() 119 | for index in 0...size) 140 | 141 | //a.values.deallocate(capacity: Int(a.size)) 142 | a.deallocate() 143 | 144 | 145 | 146 | 147 | } 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /menubar/t2/MyMenu.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import AppKit 3 | 4 | class MyMenu : NSMenu { 5 | 6 | var interface : NSMenuItem? 7 | var socket : NSMenuItem? 8 | var ip : NSMenuItem? 9 | var term : NSMenuItem? 10 | 11 | 12 | var settingsWindow : SettingsWindow? 13 | 14 | init() { 15 | super.init(title: "netfil") 16 | 17 | interface = NSMenuItem(title: "Interface filter", action: #selector(self.launchSettings), keyEquivalent: "") 18 | //interface?.onStateImage = onImage 19 | //interface?.offStateImage = offImage 20 | interface?.target = self; 21 | 22 | self.addItem(interface!) 23 | 24 | self.addItem(NSMenuItem.separator()) 25 | 26 | socket = NSMenuItem(title: "Socket filter", action: #selector(self.launchSettings), keyEquivalent: "") 27 | socket?.target = self 28 | 29 | self.addItem(socket!) 30 | 31 | self.addItem(NSMenuItem.separator()) 32 | 33 | ip = NSMenuItem(title: "IP filter", action: #selector(self.launchSettings), keyEquivalent: "") 34 | self.addItem(ip!) 35 | ip?.target = self 36 | 37 | self.addItem(NSMenuItem.separator()) 38 | 39 | term = NSMenuItem(title: "Quit netfil", action: #selector(self.terminate), keyEquivalent: "") 40 | term?.target = self 41 | self.addItem(term!) 42 | } 43 | 44 | func terminate() { 45 | exit(0) 46 | } 47 | 48 | func launchSettings(_ sender : NSMenuItem) { 49 | if((settingsWindow == nil)) { 50 | settingsWindow = SettingsWindow(contentRect:NSRect(x: 0, y: 0, width: 500, height: 200), styleMask: [NSWindowStyleMask.closable, NSWindowStyleMask.titled], backing: NSBackingStoreType.retained, defer: true, screen: NSScreen.main()) 51 | settingsWindow?.title = "netfil" 52 | settingsWindow?.isReleasedWhenClosed = false 53 | settingsWindow?.contentViewController = SettingsViewController() 54 | } 55 | 56 | if(sender == interface) { 57 | (settingsWindow?.contentViewController?.view as! NSTabView).selectTabViewItem(at: 0) 58 | } else if(sender == socket) { 59 | (settingsWindow?.contentViewController?.view as! NSTabView).selectTabViewItem(at: 1) 60 | } else { 61 | (settingsWindow?.contentViewController?.view as! NSTabView).selectTabViewItem(at: 2) 62 | } 63 | 64 | settingsWindow?.center() 65 | settingsWindow?.makeKeyAndOrderFront(self) 66 | settingsWindow?.orderFrontRegardless() 67 | settingsWindow?.makeMain() 68 | settingsWindow?.makeKey() 69 | NSApp.activate(ignoringOtherApps: true) 70 | 71 | } 72 | 73 | override func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { 74 | var ret = true 75 | 76 | if(menuItem == interface) { 77 | let status = Interface.shared.isActive 78 | switch status { 79 | case .active: 80 | interface?.image = #imageLiteral(resourceName: "Status-user-online-icon") 81 | interface?.isEnabled = true 82 | break 83 | case .inactive: 84 | interface?.image = #imageLiteral(resourceName: "Status-user-busy-icon") 85 | interface?.isEnabled = true 86 | break 87 | default: 88 | interface?.image = #imageLiteral(resourceName: "Status-user-offline-icon") 89 | ret = false 90 | break 91 | } 92 | 93 | interface?.image?.size = NSSize(width: 16, height: 16) 94 | 95 | } else if (menuItem == socket) { 96 | let status = Socket.shared.isActive 97 | switch status { 98 | case .active: 99 | socket?.image = #imageLiteral(resourceName: "Status-user-online-icon") 100 | socket?.isEnabled = true 101 | break 102 | case .inactive: 103 | socket?.image = #imageLiteral(resourceName: "Status-user-busy-icon") 104 | socket?.isEnabled = true 105 | break 106 | default: 107 | socket?.image = #imageLiteral(resourceName: "Status-user-offline-icon") 108 | ret = false 109 | break 110 | } 111 | 112 | socket?.image?.size = NSSize(width: 16, height: 16) 113 | }else if (menuItem == ip) { 114 | let status = IpFilter.shared.isActive 115 | switch status { 116 | case .active: 117 | ip?.image = #imageLiteral(resourceName: "Status-user-online-icon") 118 | ip?.isEnabled = true 119 | break 120 | case .inactive: 121 | ip?.image = #imageLiteral(resourceName: "Status-user-busy-icon") 122 | ip?.isEnabled = true 123 | break 124 | default: 125 | ip?.image = #imageLiteral(resourceName: "Status-user-offline-icon") 126 | ret = false 127 | break 128 | } 129 | 130 | ip?.image?.size = NSSize(width: 16, height: 16) 131 | }else if(menuItem == term) { 132 | return ret 133 | } 134 | return ret 135 | } 136 | 137 | required init(coder decoder: NSCoder) { 138 | fatalError("init(coder:) has not been implemented") 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /kext/iffilter/socket_filter.c: -------------------------------------------------------------------------------- 1 | #include "socket_filter.h" 2 | 3 | static sflt_handle tcp4Handler = 'tcp4'; 4 | static sflt_handle tcp6Handler = 'tcp6'; 5 | 6 | // TODO: filter every tother thing 7 | static sflt_handle udp4Handler = 'udp4'; 8 | static sflt_handle udp6Handler = 'udp6'; 9 | static sflt_handle icmp4Handler= 'icm4'; 10 | static sflt_handle icmp6Handler= 'icm6'; 11 | static sflt_handle raw4Handler = 'rip4'; 12 | static sflt_handle raw6Handler = 'rip4'; 13 | 14 | static int filtersAreRegistered = 0; 15 | 16 | static int bytes_out_since_reset = 0; 17 | static int bytes_in_since_reset = 0; 18 | 19 | static errno_t 20 | sip_attach( 21 | void **cookie, 22 | socket_t socket) 23 | { 24 | DPRINT("attached to a socket\n"); 25 | 26 | DPRINT("self socket pid %d\n", proc_selfpid()); 27 | 28 | errno_t ret = 0; 29 | 30 | // pid is not desired so don't need the filter... 31 | if(user_pid != proc_selfpid()) { // TODO: proc_selfpid may not be accurate 32 | ret = ENXIO; // See: https://lists.apple.com/archives/darwin-kernel/2006/Oct/msg00166.html 33 | } 34 | 35 | return ret; 36 | } 37 | 38 | static void 39 | sip_detach( 40 | void *cookie, 41 | socket_t socket) 42 | { 43 | DPRINT("detached socket"); 44 | } 45 | 46 | static void 47 | sip_unregistered( 48 | sflt_handle handle) 49 | { 50 | DPRINT("unregistered socket"); 51 | } 52 | 53 | static errno_t 54 | sip_sock_out( 55 | void *cookie, 56 | socket_t so, 57 | const struct sockaddr *to, 58 | mbuf_t *data, 59 | mbuf_t *control, 60 | sflt_data_flag_t flags) 61 | { 62 | DPRINT("socket data out %zu\n", mbuf_len(*data)); 63 | 64 | bytes_out_since_reset += mbuf_len(*data); 65 | 66 | if(user_socket_out_byte_limit != 0 && bytes_out_since_reset > user_socket_out_byte_limit) { 67 | return !EJUSTRETURN; 68 | } 69 | 70 | if(user_socket_io_byte_limit != 0 && (bytes_in_since_reset + bytes_out_since_reset) > user_socket_io_byte_limit) { 71 | return !EJUSTRETURN; 72 | } 73 | 74 | return 0; 75 | } 76 | 77 | static errno_t sip_sock_in(void *cookie, socket_t so, const struct sockaddr *from, mbuf_t *data, mbuf_t *control, sflt_data_flag_t flags) { 78 | DPRINT("socket data in %zu\n", mbuf_len(*data)); 79 | 80 | bytes_in_since_reset += mbuf_len(*data); 81 | 82 | if(user_socket_in_byte_limit != 0 && bytes_in_since_reset > user_socket_in_byte_limit) { 83 | return !EJUSTRETURN; 84 | } 85 | 86 | if(user_socket_io_byte_limit != 0 && (bytes_in_since_reset + bytes_out_since_reset) > user_socket_io_byte_limit) { 87 | return !EJUSTRETURN; 88 | } 89 | 90 | return 0; 91 | } 92 | 93 | errno_t socket_filter_setup() { 94 | errno_t ret = 0; 95 | 96 | user_pid = 0; 97 | 98 | socket_status = 0; 99 | 100 | return ret; 101 | } 102 | 103 | errno_t socket_filter_start() { 104 | errno_t ret = 0; 105 | 106 | if(filtersAreRegistered == 1) { 107 | return -1; 108 | } 109 | 110 | struct sflt_filter tcpFilter; 111 | bzero(&tcpFilter, sizeof(tcpFilter)); 112 | tcpFilter.sf_name = "com.company.netfil tcp ipv4 filter"; 113 | tcpFilter.sf_handle = tcp4Handler; 114 | tcpFilter.sf_flags = SFLT_GLOBAL; 115 | tcpFilter.sf_attach = sip_attach; 116 | tcpFilter.sf_detach = sip_detach; 117 | tcpFilter.sf_unregistered = sip_unregistered; 118 | tcpFilter.sf_data_out = sip_sock_out; 119 | tcpFilter.sf_data_in = sip_sock_in; 120 | ret |= sflt_register(&tcpFilter, PF_INET, SOCK_STREAM, IPPROTO_TCP); 121 | 122 | if(ret != 0) { 123 | DPRINT("failed to start ipv4 socket filter\n"); 124 | } 125 | 126 | tcpFilter.sf_name = "com.company.netfil tcp ipv6 filter"; 127 | tcpFilter.sf_handle = tcp6Handler; 128 | ret |= sflt_register(&tcpFilter, PF_INET6, SOCK_STREAM, IPPROTO_TCP); 129 | 130 | if(ret != 0) { 131 | DPRINT("failed to start ipv6 socket filter\n"); 132 | } 133 | 134 | socket_status = 1; 135 | filtersAreRegistered = 1; 136 | 137 | if(ret != 0) { 138 | socket_filter_cleanup(); 139 | } 140 | 141 | return ret; 142 | 143 | } 144 | 145 | errno_t socket_filter_stop() { 146 | errno_t ret = 0; 147 | ret = socket_filter_cleanup(); 148 | 149 | bytes_out_since_reset = 0; 150 | bytes_in_since_reset = 0; 151 | 152 | return ret; 153 | } 154 | 155 | 156 | errno_t socket_filter_cleanup() { 157 | errno_t ret = 0; 158 | 159 | ret = sflt_unregister(tcp4Handler); 160 | ret = sflt_unregister(tcp6Handler); 161 | filtersAreRegistered = 0; 162 | 163 | // ret = sflt_unregister(udp4Handler); 164 | // ret = sflt_unregister(udp6Handler); 165 | // 166 | // ret = sflt_unregister(icmp4Handler); 167 | // ret = sflt_unregister(icmp6Handler); 168 | // 169 | // ret = sflt_unregister(raw4Handler); 170 | // ret = sflt_unregister(raw6Handler); 171 | 172 | socket_status = 0; 173 | 174 | return ret; 175 | } 176 | 177 | int sysctl_socket_status_handler SYSCTL_HANDLER_ARGS { 178 | DPRINT("inside %s (%d)\n", oidp->oid_name, oidp->oid_number); 179 | 180 | int old = socket_status; 181 | 182 | int error = sysctl_handle_int(oidp, arg1, arg2, req); 183 | 184 | if (!error && req->newptr) { // write request 185 | DPRINT("write for %s %d\n", oidp->oid_name, error); 186 | DPRINT("old %d new %d\n", old, socket_status); 187 | 188 | if(old != socket_status) { 189 | DPRINT("things are different\n"); 190 | if(socket_status == 1) { 191 | if(socket_filter_start() != 0) { 192 | // some error, cleanup and set status to 0 193 | DPRINT("failed to start filter so stopping\n"); 194 | socket_filter_stop(); 195 | socket_status = 0; 196 | } 197 | } else { 198 | socket_status = 0; 199 | socket_filter_stop(); 200 | } 201 | } 202 | } else if (req->newptr) { 203 | DPRINT("write with error %d for %s\n", error, oidp->oid_name); 204 | /* Something was wrong with the write request */ 205 | /* Do something here if you feel like it.... */ 206 | } else { 207 | DPRINT("read for socket.%s=%d, %d\n", oidp->oid_name, socket_status, error); 208 | error = 0; 209 | } 210 | 211 | return error; 212 | } 213 | -------------------------------------------------------------------------------- /menubar/t2/IpViewController.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import AppKit 3 | 4 | class IpViewController : NSViewController { 5 | 6 | var button : NSButton? 7 | 8 | var addr : NSTextField? 9 | 10 | var iByte : NSTextField? 11 | var oByte : NSTextField? 12 | var ioByte : NSTextField? 13 | 14 | 15 | override func loadView() { 16 | view = NSStackView(frame: NSRect(x: 0, y: 0, width: 500, height: 0)) 17 | (view as! NSStackView).orientation = NSUserInterfaceLayoutOrientation.vertical 18 | (view as! NSStackView).spacing = CGFloat(PADDING) 19 | let titleBarSize = NSWindow.frameRect(forContentRect: self.view.frame, styleMask: NSWindowStyleMask.titled).height 20 | (view as! NSStackView).edgeInsets = EdgeInsets(top: titleBarSize, left: PADDING, bottom: PADDING, right: PADDING) 21 | //(view as! NSStackView).translatesAutoresizingMaskIntoConstraints = false 22 | } 23 | 24 | override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 25 | 26 | //super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) 27 | if(keyPath == "isActive") { 28 | statusChange() 29 | print("\(keyPath) did change here!", IpFilter.shared.isActive) 30 | } 31 | } 32 | 33 | override func viewDidLoad() { 34 | 35 | button = NSButton(title: "Go!", target: self, action: #selector(buttonPress)) 36 | 37 | let iByteName = NSTextField(string: "iByte:") 38 | iByteName.isBordered = false 39 | iByteName.isEditable = false 40 | iByteName.isSelectable = false 41 | iByteName.backgroundColor = NSColor.clear 42 | 43 | let iByteLabel = NSTextField(string: "bytes") 44 | iByteLabel.isBordered = false 45 | iByteLabel.isEditable = false 46 | iByteLabel.isSelectable = false 47 | iByteLabel.alphaValue = 0.7 48 | iByteLabel.backgroundColor = NSColor.clear 49 | 50 | iByte = NSTextField(string: String(IpFilter.shared.iByte)) 51 | iByte?.placeholderString = "0" 52 | iByte?.alignment = NSTextAlignment.right 53 | 54 | let iByteStack = NSStackView(views: [iByteName, iByte!, iByteLabel]) 55 | iByteStack.orientation = NSUserInterfaceLayoutOrientation.horizontal 56 | 57 | let oByteName = NSTextField(string: "oByte:") 58 | oByteName.isBordered = false 59 | oByteName.isEditable = false 60 | oByteName.isSelectable = false 61 | oByteName.backgroundColor = NSColor.clear 62 | 63 | let oByteLabel = NSTextField(string: "bytes") 64 | oByteLabel.isBordered = false 65 | oByteLabel.isEditable = false 66 | oByteLabel.isSelectable = false 67 | oByteLabel.alphaValue = 0.7 68 | oByteLabel.backgroundColor = NSColor.clear 69 | 70 | oByte = NSTextField(string: String(IpFilter.shared.oByte)) 71 | oByte?.placeholderString = "0" 72 | oByte?.alignment = NSTextAlignment.right 73 | 74 | let oByteStack = NSStackView(views: [oByteName, oByte!, oByteLabel]) 75 | oByteStack.orientation = NSUserInterfaceLayoutOrientation.horizontal 76 | 77 | let ioByteName = NSTextField(string: "ioByte:") 78 | ioByteName.isBordered = false 79 | ioByteName.isEditable = false 80 | ioByteName.isSelectable = false 81 | ioByteName.backgroundColor = NSColor.clear 82 | 83 | let ioByteLabel = NSTextField(string: "bytes") 84 | ioByteLabel.isBordered = false 85 | ioByteLabel.isEditable = false 86 | ioByteLabel.isSelectable = false 87 | ioByteLabel.wantsLayer = true // to enable transparency 88 | ioByteLabel.alphaValue = 0.7 89 | ioByteLabel.backgroundColor = NSColor.clear 90 | 91 | ioByte = TSTextField(string: String(IpFilter.shared.ioByte)) 92 | ioByte?.placeholderString = "0" 93 | ioByte?.alignment = NSTextAlignment.right 94 | 95 | let ioByteStack = NSStackView(views: [ioByteName, ioByte!, ioByteLabel]) 96 | ioByteStack.orientation = NSUserInterfaceLayoutOrientation.horizontal 97 | //ioByteStack.alignment = NSLayoutAttribute.right 98 | 99 | let addrName = NSTextField(string: "Address:") 100 | addrName.isBordered = false 101 | addrName.isEditable = false 102 | addrName.isSelectable = false 103 | addrName.backgroundColor = NSColor.clear 104 | 105 | addr = TSTextField() 106 | addr?.alignment = NSTextAlignment.right 107 | 108 | let addrStack = NSStackView(views: [addrName, addr!]) 109 | addrStack.orientation = NSUserInterfaceLayoutOrientation.horizontal 110 | 111 | //let parentStackView = NSStackView(views: [titleStackView, iByteStack, oByteStack, ioByteStack, mainStackView!, button!]) 112 | //parentStackView.orientation = NSUserInterfaceLayoutOrientation.vertical 113 | //parentStackView.frame.size.height = 20 114 | //parentStackView.frame.size.width = 200; 115 | //self.view = parentStackView 116 | (view as! NSStackView).addArrangedSubview(iByteStack) 117 | (view as! NSStackView).addArrangedSubview(oByteStack) 118 | (view as! NSStackView).addArrangedSubview(ioByteStack) 119 | (view as! NSStackView).addArrangedSubview(addrStack) 120 | (view as! NSStackView).addArrangedSubview(button!) 121 | 122 | 123 | 124 | IpFilter.shared.addObserver(self, forKeyPath: "isActive", options: [NSKeyValueObservingOptions.initial, NSKeyValueObservingOptions.new], context: nil) 125 | 126 | Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(checkStatus), userInfo: nil, repeats: true) 127 | } 128 | 129 | func buttonPress() { 130 | switch(IpFilter.shared.isActive) { 131 | case .active: 132 | IpFilter.shared.isActive = IpFilter.activity.inactive 133 | break 134 | case .inactive: 135 | IpFilter.shared.addr = (addr?.stringValue)! 136 | IpFilter.shared.iByte = CInt(Int((iByte?.stringValue)!)!) 137 | IpFilter.shared.oByte = CInt(Int((oByte?.stringValue)!)!) 138 | IpFilter.shared.ioByte = CInt(Int((ioByte?.stringValue)!)!) 139 | IpFilter.shared.isActive = IpFilter.activity.active 140 | break 141 | default: 142 | break 143 | } 144 | statusChange() 145 | } 146 | 147 | func statusChange() { 148 | let s = IpFilter.shared.isActive 149 | lastStatus = s 150 | switch(IpFilter.shared.isActive) { 151 | case .active: 152 | button?.title = "Stop" 153 | button?.isEnabled = true 154 | break 155 | case .inactive: 156 | button?.title = "Filter" 157 | button?.isEnabled = true 158 | break 159 | default: 160 | button?.title = "Filter" 161 | button?.isEnabled = false 162 | } 163 | } 164 | 165 | var lastStatus : IpFilter.activity = IpFilter.activity.unknown 166 | func checkStatus() { 167 | 168 | // This is necessary cause our KVO only detects changes 169 | // that we make, not that the kernel makes, or other 170 | // external programs 171 | 172 | if IpFilter.shared.isActive != lastStatus { 173 | statusChange() 174 | } 175 | } 176 | 177 | } 178 | -------------------------------------------------------------------------------- /menubar/t2/SocketViewController.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import AppKit 3 | 4 | class SocketViewController : NSViewController { 5 | 6 | var button : NSButton? 7 | 8 | var pid : NSTextField? 9 | 10 | var iByte : NSTextField? 11 | var oByte : NSTextField? 12 | var ioByte : NSTextField? 13 | 14 | 15 | override func loadView() { 16 | view = NSStackView(frame: NSRect(x: 0, y: 0, width: 500, height: 0)) 17 | (view as! NSStackView).orientation = NSUserInterfaceLayoutOrientation.vertical 18 | (view as! NSStackView).spacing = CGFloat(PADDING) 19 | let titleBarSize = NSWindow.frameRect(forContentRect: self.view.frame, styleMask: NSWindowStyleMask.titled).height 20 | (view as! NSStackView).edgeInsets = EdgeInsets(top: titleBarSize, left: PADDING, bottom: PADDING, right: PADDING) 21 | //(view as! NSStackView).translatesAutoresizingMaskIntoConstraints = false 22 | } 23 | 24 | override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 25 | 26 | //super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) 27 | if(keyPath == "isActive") { 28 | statusChange() 29 | print("\(keyPath) did change here!", Socket.shared.isActive) 30 | } 31 | } 32 | 33 | override func viewDidLoad() { 34 | 35 | button = NSButton(title: "Go!", target: self, action: #selector(buttonPress)) 36 | 37 | let iByteName = NSTextField(string: "iByte:") 38 | iByteName.isBordered = false 39 | iByteName.isEditable = false 40 | iByteName.isSelectable = false 41 | iByteName.backgroundColor = NSColor.clear 42 | 43 | let iByteLabel = NSTextField(string: "bytes") 44 | iByteLabel.isBordered = false 45 | iByteLabel.isEditable = false 46 | iByteLabel.isSelectable = false 47 | iByteLabel.alphaValue = 0.7 48 | iByteLabel.backgroundColor = NSColor.clear 49 | 50 | iByte = NSTextField(string: String(Socket.shared.iByte)) 51 | iByte?.placeholderString = "0" 52 | iByte?.alignment = NSTextAlignment.right 53 | 54 | let iByteStack = NSStackView(views: [iByteName, iByte!, iByteLabel]) 55 | iByteStack.orientation = NSUserInterfaceLayoutOrientation.horizontal 56 | 57 | let oByteName = NSTextField(string: "oByte:") 58 | oByteName.isBordered = false 59 | oByteName.isEditable = false 60 | oByteName.isSelectable = false 61 | oByteName.backgroundColor = NSColor.clear 62 | 63 | let oByteLabel = NSTextField(string: "bytes") 64 | oByteLabel.isBordered = false 65 | oByteLabel.isEditable = false 66 | oByteLabel.isSelectable = false 67 | oByteLabel.alphaValue = 0.7 68 | oByteLabel.backgroundColor = NSColor.clear 69 | 70 | oByte = NSTextField(string: String(Socket.shared.oByte)) 71 | oByte?.placeholderString = "0" 72 | oByte?.alignment = NSTextAlignment.right 73 | 74 | let oByteStack = NSStackView(views: [oByteName, oByte!, oByteLabel]) 75 | oByteStack.orientation = NSUserInterfaceLayoutOrientation.horizontal 76 | 77 | let ioByteName = NSTextField(string: "ioByte:") 78 | ioByteName.isBordered = false 79 | ioByteName.isEditable = false 80 | ioByteName.isSelectable = false 81 | ioByteName.backgroundColor = NSColor.clear 82 | 83 | let ioByteLabel = NSTextField(string: "bytes") 84 | ioByteLabel.isBordered = false 85 | ioByteLabel.isEditable = false 86 | ioByteLabel.isSelectable = false 87 | ioByteLabel.wantsLayer = true // to enable transparency 88 | ioByteLabel.alphaValue = 0.7 89 | ioByteLabel.backgroundColor = NSColor.clear 90 | 91 | ioByte = TSTextField(string: String(Socket.shared.ioByte)) 92 | ioByte?.placeholderString = "0" 93 | ioByte?.alignment = NSTextAlignment.right 94 | 95 | let ioByteStack = NSStackView(views: [ioByteName, ioByte!, ioByteLabel]) 96 | ioByteStack.orientation = NSUserInterfaceLayoutOrientation.horizontal 97 | //ioByteStack.alignment = NSLayoutAttribute.right 98 | 99 | let pidName = NSTextField(string: "PID:") 100 | pidName.isBordered = false 101 | pidName.isEditable = false 102 | pidName.isSelectable = false 103 | pidName.backgroundColor = NSColor.clear 104 | 105 | pid = TSTextField(string: String(Socket.shared.pid)) 106 | pid?.placeholderString = "0" 107 | pid?.alignment = NSTextAlignment.right 108 | 109 | let pidStack = NSStackView(views: [pidName, pid!]) 110 | pidStack.orientation = NSUserInterfaceLayoutOrientation.horizontal 111 | 112 | //let parentStackView = NSStackView(views: [titleStackView, iByteStack, oByteStack, ioByteStack, mainStackView!, button!]) 113 | //parentStackView.orientation = NSUserInterfaceLayoutOrientation.vertical 114 | //parentStackView.frame.size.height = 20 115 | //parentStackView.frame.size.width = 200; 116 | //self.view = parentStackView 117 | (view as! NSStackView).addArrangedSubview(iByteStack) 118 | (view as! NSStackView).addArrangedSubview(oByteStack) 119 | (view as! NSStackView).addArrangedSubview(ioByteStack) 120 | (view as! NSStackView).addArrangedSubview(pidStack) 121 | (view as! NSStackView).addArrangedSubview(button!) 122 | 123 | 124 | 125 | IpFilter.shared.addObserver(self, forKeyPath: "isActive", options: [NSKeyValueObservingOptions.initial, NSKeyValueObservingOptions.new], context: nil) 126 | 127 | Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(checkStatus), userInfo: nil, repeats: true) 128 | } 129 | 130 | func buttonPress() { 131 | switch(Socket.shared.isActive) { 132 | case .active: 133 | Socket.shared.isActive = Socket.activity.inactive 134 | break 135 | case .inactive: 136 | Socket.shared.pid = CInt(Int((pid?.stringValue)!)!) 137 | Socket.shared.iByte = CInt(Int((iByte?.stringValue)!)!) 138 | Socket.shared.oByte = CInt(Int((oByte?.stringValue)!)!) 139 | Socket.shared.ioByte = CInt(Int((ioByte?.stringValue)!)!) 140 | Socket.shared.isActive = Socket.activity.active 141 | break 142 | default: 143 | break 144 | } 145 | statusChange() 146 | } 147 | 148 | func statusChange() { 149 | let s = Socket.shared.isActive 150 | lastStatus = s 151 | switch(Socket.shared.isActive) { 152 | case .active: 153 | button?.title = "Stop" 154 | button?.isEnabled = true 155 | break 156 | case .inactive: 157 | button?.title = "Filter" 158 | button?.isEnabled = true 159 | break 160 | default: 161 | button?.title = "Filter" 162 | button?.isEnabled = false 163 | } 164 | } 165 | 166 | var lastStatus : Socket.activity = Socket.activity.unknown 167 | func checkStatus() { 168 | 169 | // This is necessary cause our KVO only detects changes 170 | // that we make, not that the kernel makes, or other 171 | // external programs 172 | 173 | if Socket.shared.isActive != lastStatus { 174 | statusChange() 175 | } 176 | } 177 | 178 | } 179 | -------------------------------------------------------------------------------- /kext/iffilter/interface_filter.h: -------------------------------------------------------------------------------- 1 | // https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/interface_filter_nke/interface_filter_nke.html#//apple_ref/doc/uid/TP40001858-CH230-SW1 2 | 3 | #ifndef interface_filter_h 4 | #define interface_filter_h 5 | 6 | #include "common.h" 7 | #include // includes functions for filtering at the raw packet level, just above the network interface layer. These functions are appropriate for an interface filter. 8 | 9 | struct filters { 10 | int id; 11 | interface_filter_t ref; 12 | struct iff_filter filter; 13 | 14 | struct kev_msg *last_event_msg; 15 | unsigned long last_ioctl_cmd; 16 | void * last_ioctl_arg; 17 | mbuf_t *last_in_data; 18 | char **last_frame_ptr; 19 | mbuf_t *last_out_data; 20 | 21 | time_t reset; 22 | u_int64_t bytes_out_since_reset; 23 | u_int64_t bytes_in_since_reset; 24 | }; 25 | 26 | /** 27 | * input output byte limit for interface filter 28 | * 29 | * 0 is unlimted or no limit (default) 30 | **/ 31 | extern int user_interface_io_byte_limit; 32 | /** 33 | * input byte limit for interface filter 34 | * 35 | * 0 is unlimted or no limit (default) 36 | **/ 37 | extern int user_interface_in_byte_limit; 38 | /** 39 | * output byte limit for interface filter 40 | * 41 | * 0 is unlimted or no limit (default) 42 | **/ 43 | extern int user_interface_out_byte_limit; 44 | 45 | /** 46 | * flag to determine if currently filtering interfaces 47 | **/ 48 | extern int interface_status; 49 | 50 | /** 51 | * iff_ioctl_func is used to filter ioctls sent to an interface. The interface is only valid for the 52 | * duration of the filter call. If you need to keep a reference to the interface, be sure to call 53 | * ifnet_reference and ifnet_release. 54 | * 55 | * All undefined ioctls are reserved for future use by Apple. If you need to communicate with your 56 | * kext using an ioctl, please use SIOCSIFKPI and SIOCGIFKPI. 57 | * 58 | * @param cookie The cookie specified when this filter was attached. 59 | * @param interface The interface the packet is being transmitted on. 60 | * @param protocol The protocol of this packet. If you specified a protocol when 61 | * attaching your filter, the protocol will only ever be the protocol you specified. 62 | * @param ioctl_cmd The ioctl command. 63 | * @param ioctl_arg A pointer to the ioctl argument. 64 | * 65 | * @result 0 - This filter function handled the ioctl. EOPNOTSUPP - This filter function does not 66 | * understand/did not handle this ioctl. EJUSTRETURN - This filter function handled the ioctl, 67 | * processing should stop. Anything Else - Processing will stop, the error will be returned. 68 | **/ 69 | errno_t ioctl_handler(void *cookie, ifnet_t interface, protocol_family_t protocol, unsigned long ioctl_cmd, void *ioctl_arg); 70 | 71 | /** 72 | * iff_event_func is used to filter interface specific events. The interface is only valid for the 73 | * duration of the filter call. If you need to keep a reference to the interface, be sure to call 74 | * ifnet_reference and ifnet_release. 75 | * 76 | * @param cookie The cookie specified when this filter was attached. 77 | * @param interface The interface the packet is being transmitted on. 78 | * @param protocol The protocol of this packet. If you specified a protocol when 79 | * attaching your filter, the protocol will only ever be the protocol you specified. 80 | * @param event_msg The kernel event, may not be changed. 81 | **/ 82 | void event_handler(void *cookie, ifnet_t interface, protocol_family_t protocol, const struct kev_msg *event_msg); 83 | 84 | /** 85 | * iff_output_func is used to filter fully formed outbound packets. The interface is only valid 86 | * for the duration of the filter call. If you need to keep a reference to the interface, be sure 87 | * to call ifnet_reference and ifnet_release. 88 | * 89 | * @param cookie The cookie specified when this filter was attached. 90 | * @param interface The interface the packet is being transmitted on. 91 | * @param protocol The protocol of this packet. If you specified a protocol when 92 | * attaching your filter, the protocol will only ever be the protocol you specified. 93 | * @param data The fully formed outbound packet in a chain of mbufs. The frame header is 94 | * already included. The filter function may modify the packet or return a different mbuf chain. 95 | * 96 | * @result 0 - The caller will continue with normal processing of the packet. 97 | * EJUSTRETURN - The caller will stop processing the packet, the packet will not be freed. 98 | * Anything Else - The caller will free the packet and stop processing. 99 | **/ 100 | errno_t out_handler(void *cookie, ifnet_t interface, protocol_family_t protocol, mbuf_t *data); 101 | 102 | /** 103 | * iff_input_func is used to filter incoming packets. The interface is only valid for the 104 | * duration of the filter call. If you need to keep a reference to the interface, be sure 105 | * to call ifnet_reference and ifnet_release. The packets passed to the inbound filter are 106 | * different from those passed to the outbound filter. Packets to the inbound filter have 107 | * the frame header passed in separately from the rest of the packet. The outbound data 108 | * filters is passed the whole packet including the frame header. 109 | * 110 | * The frame header usually preceeds the data in the mbuf. This ensures that the frame header 111 | * will be a valid pointer as long as the mbuf is not freed. If you need to change the frame 112 | * header to point somewhere else, the recommended method is to prepend a new frame header to 113 | * the mbuf chain (mbuf_prepend), set the header to point to that data, then call mbuf_adj to 114 | * move the mbuf data pointer back to the start of the packet payload. 115 | * 116 | * @param cookie The cookie specified when this filter was attached. 117 | * @param interface The interface the packet was recieved on. 118 | * @param protocol The protocol of this packet. If you specified a protocol when 119 | * attaching your filter, the protocol will only ever be the protocol you specified. 120 | * @param data The inbound packet, after the frame header as determined by the interface. 121 | * @param frame_ptr A pointer to the pointer to the frame header. The frame header 122 | * length can be found by inspecting the interface's frame header length (ifnet_hdrlen). 123 | * 124 | * @result 0 - The caller will continue with normal processing of the packet. 125 | * EJUSTRETURN - The caller will stop processing the packet, the packet will not be freed. 126 | * Anything Else - The caller will free the packet and stop processing. 127 | * 128 | **/ 129 | errno_t in_handler(void *cookie, ifnet_t interface, protocol_family_t protocol, mbuf_t *data, char **frame_ptr); 130 | 131 | /** 132 | * must call interface_filter_stop before exiting 133 | * @result 0 on success, error otherwise 134 | **/ 135 | errno_t interface_filter_start(); 136 | 137 | /** 138 | * @result 0 on success, error otherwise 139 | **/ 140 | errno_t interface_filter_stop(); 141 | 142 | /** 143 | * set the interfaces 144 | * handler for settings the user-defined interface list 145 | * @param oidp id 146 | * @param arg1 first argument 147 | * @param arg2 second argument 148 | * @param req the request 149 | **/ 150 | int sysctl_iff_interfaces_handler SYSCTL_HANDLER_ARGS; 151 | 152 | /** 153 | * status of filtering for interfaces 154 | * can be used to start or stop the interface filter 155 | * or see if the filter is currently active 156 | * 157 | * takes an integer as an argument 158 | * @param oidp id 159 | * @param arg1 first argument 160 | * @param arg2 second argument 161 | * @param req the request 162 | **/ 163 | int sysctl_iff_status_handler SYSCTL_HANDLER_ARGS; 164 | 165 | /** 166 | * frees user defined interface list 167 | * @return 0 on success 168 | **/ 169 | int freeUserInterfaces(); 170 | 171 | /** 172 | * initial setup for the interface filter 173 | * @return 0 on success 174 | **/ 175 | kern_return_t interface_filter_setup(); 176 | 177 | /** 178 | * final cleanup for the interface filter 179 | * @return 0 on success 180 | **/ 181 | kern_return_t interface_filter_cleanup(); 182 | 183 | #endif /* interface_filter_h */ 184 | -------------------------------------------------------------------------------- /kext/iffilter/ip_filter.c: -------------------------------------------------------------------------------- 1 | #include "ip_filter.h" 2 | 3 | static ipfilter_t ipv4Filter; 4 | static u_int32_t ipv4COOKIE = 'ipv4'; 5 | 6 | 7 | static ipfilter_t ipv6Filter; 8 | static u_int32_t ipv6COOKIE = 'ipv6'; 9 | 10 | static struct in_addr ipv4Addr = {0}; 11 | static struct in6_addr ipv6Addr = {0}; 12 | 13 | static int bytes_out_since_reset = 0; 14 | static int bytes_in_since_reset = 0; 15 | 16 | void ipf_detach_handler(void *cookie) { 17 | } 18 | 19 | kern_return_t ip_filter_setup() { 20 | kern_return_t ret = KERN_SUCCESS; 21 | 22 | ipv4Filter = NULL; 23 | ipv6Filter = NULL; 24 | 25 | return ret; 26 | } 27 | 28 | errno_t ipf_input_handler(void *cookie, mbuf_t *data, int offset, u_int8_t protocol) { 29 | bytes_in_since_reset += mbuf_len(*data); 30 | 31 | char srcStr[INET6_ADDRSTRLEN] = {0}; 32 | char dstStr[INET6_ADDRSTRLEN] = {0}; 33 | 34 | if(cookie == &ipv4COOKIE) { 35 | //DPRINT("ipv4 cookie!\n"); 36 | if(mbuf_len(*data) >= sizeof(struct ip)) { 37 | struct ip *iii = (struct ip*) data; 38 | inet_ntop(AF_INET, &(iii->ip_dst), dstStr, INET_ADDRSTRLEN); 39 | inet_ntop(AF_INET, &(iii->ip_src), srcStr, INET_ADDRSTRLEN); 40 | //iii->ip_dst; 41 | //iii->ip_src; 42 | } 43 | } else if(cookie == &ipv6COOKIE){ 44 | //DPRINT("ipv6 cookie!\n"); 45 | if(mbuf_len(*data) >= sizeof(struct ip6_hdr)) { 46 | struct ip6_hdr *iii = (struct ip6_hdr *) data; 47 | //iii->ip6_dst; 48 | //iii->ip6_src; 49 | inet_ntop(AF_INET6, &(iii->ip6_dst), dstStr, INET6_ADDRSTRLEN); 50 | inet_ntop(AF_INET6, &(iii->ip6_src), srcStr, INET6_ADDRSTRLEN); 51 | } 52 | } else { 53 | DPRINT("Unknown cookie! %p\n", cookie); 54 | return 0; 55 | } 56 | 57 | //DPRINT("src %s; dst %s", srcStr, dstStr); 58 | 59 | 60 | 61 | 62 | if(user_ip_in_byte_limit != 0 && bytes_in_since_reset > user_ip_in_byte_limit) { 63 | return !EJUSTRETURN; 64 | } 65 | 66 | if(user_ip_io_byte_limit != 0 && (bytes_in_since_reset + bytes_out_since_reset) > user_ip_io_byte_limit) { 67 | return !EJUSTRETURN; 68 | } 69 | 70 | return 0; 71 | }; 72 | 73 | errno_t ipf_output_handler(void *cookie, mbuf_t *data, ipf_pktopts_t options) { 74 | bytes_out_since_reset += mbuf_len(*data); 75 | 76 | char srcStr[INET6_ADDRSTRLEN] = {0}; 77 | char dstStr[INET6_ADDRSTRLEN] = {0}; 78 | 79 | if(cookie == &ipv4COOKIE) { 80 | //DPRINT("ipv4 cookie!\n"); 81 | if(mbuf_len(*data) >= sizeof(struct ip)) { 82 | struct ip *iii = (struct ip*) data; 83 | inet_ntop(AF_INET, &(iii->ip_dst), dstStr, INET_ADDRSTRLEN); 84 | inet_ntop(AF_INET, &(iii->ip_src), srcStr, INET_ADDRSTRLEN); 85 | } 86 | } else if(cookie == &ipv6COOKIE){ 87 | //DPRINT("ipv6 cookie!\n"); 88 | if(mbuf_len(*data) >= sizeof(struct ip6_hdr)) { 89 | struct ip6_hdr *iii = (struct ip6_hdr *) data; 90 | //iii->ip6_dst; 91 | //iii->ip6_src; 92 | inet_ntop(AF_INET6, &(iii->ip6_dst), dstStr, INET6_ADDRSTRLEN); 93 | inet_ntop(AF_INET6, &(iii->ip6_src), srcStr, INET6_ADDRSTRLEN); 94 | } 95 | } else { 96 | DPRINT("Unknown cookie! %p\n", cookie); 97 | return 0; 98 | } 99 | 100 | //DPRINT("src %s; dst %s", srcStr, dstStr); 101 | 102 | if(user_ip_out_byte_limit != 0 && bytes_out_since_reset > user_ip_out_byte_limit) { 103 | return !EJUSTRETURN; 104 | } 105 | 106 | if(user_ip_io_byte_limit != 0 && (bytes_in_since_reset + bytes_out_since_reset) > user_ip_io_byte_limit) { 107 | return !EJUSTRETURN; 108 | } 109 | 110 | return 0; 111 | } 112 | 113 | /** 114 | * final cleanup for the ip filter 115 | * @return 0 on success 116 | **/ 117 | kern_return_t ip_filter_cleanup() { 118 | kern_return_t ret = KERN_SUCCESS; 119 | 120 | ret |= ip_filter_stop(); 121 | 122 | return ret; 123 | } 124 | 125 | errno_t ip_filter_start() { 126 | errno_t ret = KERN_SUCCESS; 127 | 128 | bytes_out_since_reset = 0; 129 | bytes_in_since_reset = 0; 130 | 131 | //struct ipf_fiter ipff; 132 | struct ipf_filter ipff; 133 | ipff.ipf_detach = ipf_detach_handler; 134 | ipff.ipf_input = ipf_input_handler; 135 | ipff.ipf_output = ipf_output_handler; 136 | 137 | ipff.cookie = &ipv4COOKIE; 138 | ipff.name = "netfil ipv4 filter"; 139 | ret |= ipf_addv4(&ipff, &ipv4Filter); 140 | 141 | ipff.cookie = &ipv6COOKIE; 142 | ipff.name = "netfil ipv6 filter"; 143 | ret |= ipf_addv6(&ipff, &ipv6Filter); 144 | 145 | ip_status = 1; 146 | 147 | return ret; 148 | } 149 | errno_t ip_filter_stop() { 150 | errno_t ret = KERN_SUCCESS; 151 | 152 | ipf_remove(ipv4Filter); 153 | ipf_remove(ipv6Filter); 154 | 155 | ipv4Filter = NULL; 156 | ipv6Filter = NULL; 157 | 158 | bytes_out_since_reset = 0; 159 | bytes_in_since_reset = 0; 160 | 161 | bzero(&ipv4Addr, sizeof(ipv4Addr)); 162 | bzero(&ipv6Addr, sizeof(ipv6Addr)); 163 | 164 | ip_status = 0; 165 | return ret; 166 | } 167 | 168 | int sysctl_ip_addr_handler SYSCTL_HANDLER_ARGS { 169 | DPRINT("inside %s (%d)\n", oidp->oid_name, oidp->oid_number); 170 | 171 | struct in_addr r; 172 | int error = SYSCTL_IN(req, &r, sizeof(r)); 173 | 174 | if(error) { 175 | struct in6_addr r2; 176 | error = SYSCTL_IN(req, &r2, sizeof(r2)); 177 | } 178 | 179 | // TODO: do a check for just a string... inet_pton 180 | 181 | if (!error && req->newptr) { 182 | DPRINT("size of ip addr %zu\n", req->newlen); 183 | 184 | bzero(&ipv4Addr, sizeof(ipv4Addr)); 185 | bzero(&ipv6Addr, sizeof(ipv6Addr)); 186 | 187 | if(req->newlen == sizeof(struct in_addr)) { 188 | error = copyin(req->newptr, &ipv4Addr, sizeof(struct in_addr)); 189 | 190 | char srcStr[INET6_ADDRSTRLEN] = {0}; 191 | inet_ntop(AF_INET, &ipv4Addr, srcStr, INET_ADDRSTRLEN); 192 | DPRINT("new ip? %s\n", srcStr); 193 | 194 | } else if(req->newlen == sizeof(struct in6_addr)) { 195 | error = copyin(req->newptr, &ipv6Addr, sizeof(struct in6_addr)); 196 | 197 | } else { 198 | DPRINT("unknown size of user data\n"); 199 | return -1; 200 | } 201 | } else if (req->newptr) { 202 | /* Something was wrong with the write request */ 203 | /* Do something here if you feel like it.... */ 204 | DPRINT("some error when copying... %d %zu\n", error, req->newlen); 205 | } else { 206 | /* Read request. Always return 763, just for grins. */ 207 | DPRINT("sysctl %s: read\n", oidp->oid_name); 208 | 209 | if(req->oldptr && req->oldlen == sizeof(struct in_addr)) { 210 | SYSCTL_OUT(req, &ipv4Addr, sizeof(struct in_addr)); 211 | } else if(req->oldptr && req->oldlen == sizeof(struct in6_addr)) { 212 | SYSCTL_OUT(req, &ipv6Addr, sizeof(struct in6_addr)); 213 | } 214 | 215 | } 216 | 217 | return 0; 218 | } 219 | 220 | int sysctl_ip_status_handler SYSCTL_HANDLER_ARGS { 221 | DPRINT("inside ip.%s (%d)\n", oidp->oid_name, oidp->oid_number); 222 | 223 | int old = ip_status; 224 | 225 | int error = sysctl_handle_int(oidp, arg1, arg2, req); 226 | 227 | if (!error && req->newptr) { // write request 228 | DPRINT("write for ip.%s %d\n", oidp->oid_name, error); 229 | DPRINT("old %d new %d\n", old, ip_status); 230 | 231 | if(old != ip_status) { 232 | DPRINT("things are different\n"); 233 | if(ip_status == 1) { 234 | if(ip_filter_start() != 0) { 235 | // some error, cleanup and set status to 0 236 | ip_filter_stop(); 237 | ip_status = 0; 238 | } 239 | } else { 240 | ip_status = 0; 241 | ip_filter_stop(); 242 | } 243 | } 244 | } else if (req->newptr) { 245 | DPRINT("write with error %d for %s\n", error, oidp->oid_name); 246 | /* Something was wrong with the write request */ 247 | /* Do something here if you feel like it.... */ 248 | } else { 249 | DPRINT("read for ip.%s=%d %d\n", oidp->oid_name, ip_status, error); 250 | error = 0; 251 | } 252 | 253 | return error; 254 | } 255 | -------------------------------------------------------------------------------- /kext/iffilter/netfil.c: -------------------------------------------------------------------------------- 1 | /** 2 | * This is the main file for com.company.netfil 3 | * The sysctls are defined here as with each filters' setup and cleanup functions 4 | **/ 5 | 6 | #include "interface_filter.h" 7 | #include "socket_filter.h" 8 | #include "ip_filter.h" 9 | 10 | kern_return_t iffilter_start(kmod_info_t * ki, void *d); 11 | kern_return_t iffilter_stop(kmod_info_t *ki, void *d); 12 | 13 | /** 14 | * this is the globlal OS Malloc tag for this application 15 | * all uses for OSMalloc/Free will use this tag 16 | **/ 17 | OSMallocTag globalOSMallocTag = NULL; 18 | 19 | // Boundary crossing, sysctl 20 | // https://developer.apple.com/library/content/documentation/Darwin/Conceptual/KernelProgramming/boundaries/boundaries.html#//apple_ref/doc/uid/TP30000905-CH217-BABJJBHG 21 | 22 | // setup the root net.netfil sysctl 23 | SYSCTL_NODE(_net, // our parent 24 | OID_AUTO , // automatically assign us an object ID 25 | netfil , // our name 26 | CTLFLAG_RW, // we wil be creating children therefore , read/write 27 | 0, // Handler function ( none selected ) 28 | BNAME 29 | ); 30 | 31 | // _ _ __ 32 | // (_) | | / _| 33 | // _ _ __ | |_ ___ _ __| |_ __ _ ___ ___ 34 | // | | '_ \| __/ _ \ '__| _/ _` |/ __/ _ \ 35 | // | | | | | || __/ | | || (_| | (_| __/ 36 | // |_|_| |_|\__\___|_| |_| \__,_|\___\___| 37 | 38 | SYSCTL_NODE(_net_netfil, // our parent 39 | OID_AUTO , // automatically assign us an object ID 40 | interface , // our name 41 | CTLFLAG_RW, // we wil be creating children therefore , read/write 42 | 0, // Handler function ( none selected ) 43 | BNAME 44 | ); 45 | 46 | SYSCTL_PROC(_net_netfil_interface, //our parent 47 | OID_AUTO, // automaticall assign us an object ID 48 | list, //our name 49 | CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_ANYBODY, //access flag ( read/write by anybody ) 50 | NULL, // location of our data 51 | 0, //argument passed to our handler 52 | sysctl_iff_interfaces_handler, // our handler function 53 | "S,array", // our date type 54 | "interfaces to use"); // our description 55 | 56 | int interface_status = 0; 57 | SYSCTL_PROC(_net_netfil_interface, //our parent 58 | OID_AUTO, // automaticall assign us an object ID 59 | status, //our name 60 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLTYPE_INT, //access flag ( read/write by anybody ) 61 | &interface_status, // location of our data 62 | 0, //argument passed to our handler 63 | sysctl_iff_status_handler, // our handler function 64 | "I", // our date type 65 | "interface filter status"); // our description 66 | 67 | int user_interface_io_byte_limit = 0; 68 | SYSCTL_INT(_net_netfil_interface, 69 | OID_AUTO, 70 | iobyte, 71 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 72 | &user_interface_io_byte_limit, 73 | 0, 74 | "Network interface i/o byte limit") 75 | 76 | int user_interface_in_byte_limit = 0; 77 | SYSCTL_INT(_net_netfil_interface, 78 | OID_AUTO, 79 | ibyte, 80 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 81 | &user_interface_in_byte_limit, 82 | 0, 83 | "Network interface in byte limit"); 84 | 85 | int user_interface_out_byte_limit = 0; 86 | SYSCTL_INT(_net_netfil_interface, 87 | OID_AUTO, 88 | obyte, 89 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 90 | &user_interface_out_byte_limit, 91 | 0, 92 | "Network interface out byte limit"); 93 | 94 | 95 | // _ _ 96 | // | | | | 97 | // ___ ___ ___| | _____| |_ 98 | // / __|/ _ \ / __| |/ / _ \ __| 99 | // \__ \ (_) | (__| < __/ |_ 100 | // |___/\___/ \___|_|\_\___|\__| 101 | 102 | 103 | SYSCTL_NODE(_net_netfil, // our parent 104 | OID_AUTO , // automatically assign us an object ID 105 | socket , // our name 106 | CTLFLAG_RW, // we wil be creating children therefore , read/write 107 | 0, // Handler function ( none selected ) 108 | BNAME 109 | ); 110 | 111 | int socket_status = 0; 112 | SYSCTL_PROC(_net_netfil_socket, //our parent 113 | OID_AUTO, // automaticall assign us an object ID 114 | status, //our name 115 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLTYPE_INT, //access flag ( read/write by anybody ) 116 | &socket_status, // location of our data 117 | 0, //argument passed to our handler 118 | sysctl_socket_status_handler, // our handler function 119 | "I", // our date type 120 | "socket filter status"); // our description 121 | 122 | int user_pid = 0; 123 | SYSCTL_INT(_net_netfil_socket, 124 | OID_AUTO, 125 | pid, 126 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 127 | &user_pid, 128 | 0, 129 | "Process ID"); 130 | 131 | int user_socket_io_byte_limit = 0; 132 | SYSCTL_INT(_net_netfil_socket, 133 | OID_AUTO, 134 | iobyte, 135 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 136 | &user_socket_io_byte_limit, 137 | 0, 138 | "Network socket i/o byte limit") 139 | 140 | int user_socket_in_byte_limit = 0; 141 | SYSCTL_INT(_net_netfil_socket, 142 | OID_AUTO, 143 | ibyte, 144 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 145 | &user_socket_in_byte_limit, 146 | 0, 147 | "Network socket in byte limit"); 148 | 149 | int user_socket_out_byte_limit = 0; 150 | SYSCTL_INT(_net_netfil_socket, 151 | OID_AUTO, 152 | obyte, 153 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 154 | &user_socket_out_byte_limit, 155 | 0, 156 | "Network socket out byte limit"); 157 | 158 | // _ 159 | // (_) 160 | // _ _ __ 161 | // | | '_ \ 162 | // | | |_) | 163 | // |_| .__/ 164 | // | | 165 | // |_| 166 | 167 | SYSCTL_NODE(_net_netfil, // our parent 168 | OID_AUTO , // automatically assign us an object ID 169 | ip, // our name 170 | CTLFLAG_RW, // we wil be creating children therefore , read/write 171 | 0, // Handler function ( none selected ) 172 | BNAME 173 | ); 174 | 175 | int ip_status = 0; 176 | SYSCTL_PROC(_net_netfil_ip, //our parent 177 | OID_AUTO, // automaticall assign us an object ID 178 | status, //our name 179 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLTYPE_INT, //access flag ( read/write by anybody ) 180 | &ip_status, // location of our data 181 | 0, //argument passed to our handler 182 | sysctl_ip_status_handler, // our handler function 183 | "I", // our date type 184 | "Network IP filter status"); // our description 185 | 186 | SYSCTL_PROC(_net_netfil_ip, //our parent 187 | OID_AUTO, // automaticall assign us an object ID 188 | addr, //our name 189 | CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_ANYBODY, //access flag ( read/write by anybody ) 190 | NULL, // location of our data 191 | 0, //argument passed to our handler 192 | sysctl_ip_addr_handler, // our handler function 193 | "S,array", // our date type 194 | "interfaces to use"); // our description 195 | 196 | int user_ip_io_byte_limit = 0; 197 | SYSCTL_INT(_net_netfil_ip, 198 | OID_AUTO, 199 | iobyte, 200 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 201 | &user_ip_io_byte_limit, 202 | 0, 203 | "Network IP i/o byte limit") 204 | 205 | int user_ip_in_byte_limit = 0; 206 | SYSCTL_INT(_net_netfil_ip, 207 | OID_AUTO, 208 | ibyte, 209 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 210 | &user_ip_in_byte_limit, 211 | 0, 212 | "Network IP in byte limit"); 213 | 214 | int user_ip_out_byte_limit = 0; 215 | SYSCTL_INT(_net_netfil_ip, 216 | OID_AUTO, 217 | obyte, 218 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 219 | &user_ip_out_byte_limit, 220 | 0, 221 | "Network socket out byte limit"); 222 | 223 | /** 224 | * Unregisters all sysctls and run each filters' cleanup functions 225 | * 226 | * @returns 0 on success, error otherwise 227 | **/ 228 | kern_return_t cleanup() { 229 | kern_return_t ret = KERN_SUCCESS; 230 | 231 | sysctl_unregister_oid(&sysctl__net_netfil); 232 | 233 | sysctl_unregister_oid(&sysctl__net_netfil_interface); 234 | sysctl_unregister_oid(&sysctl__net_netfil_interface_list); 235 | sysctl_unregister_oid(&sysctl__net_netfil_interface_iobyte); 236 | sysctl_unregister_oid(&sysctl__net_netfil_interface_ibyte); 237 | sysctl_unregister_oid(&sysctl__net_netfil_interface_obyte); 238 | sysctl_unregister_oid(&sysctl__net_netfil_interface_status); 239 | 240 | sysctl_unregister_oid(&sysctl__net_netfil_socket); 241 | sysctl_unregister_oid(&sysctl__net_netfil_socket_pid); 242 | sysctl_unregister_oid(&sysctl__net_netfil_socket_iobyte); 243 | sysctl_unregister_oid(&sysctl__net_netfil_socket_ibyte); 244 | sysctl_unregister_oid(&sysctl__net_netfil_socket_obyte); 245 | sysctl_unregister_oid(&sysctl__net_netfil_socket_status); 246 | 247 | sysctl_unregister_oid(&sysctl__net_netfil_ip); 248 | sysctl_unregister_oid(&sysctl__net_netfil_ip_iobyte); 249 | sysctl_unregister_oid(&sysctl__net_netfil_ip_ibyte); 250 | sysctl_unregister_oid(&sysctl__net_netfil_ip_obyte); 251 | sysctl_unregister_oid(&sysctl__net_netfil_ip_addr); 252 | sysctl_unregister_oid(&sysctl__net_netfil_ip_status); 253 | 254 | if(interface_filter_cleanup() != 0) { 255 | DPRINT("Failed to cleanup interface filter\n"); 256 | ret = KERN_FAILURE; 257 | } 258 | 259 | if(socket_filter_cleanup() != 0) { 260 | DPRINT("Failed to cleanup socket filter\n"); 261 | ret = KERN_FAILURE; 262 | } 263 | 264 | if(ip_filter_cleanup() != 0) { 265 | DPRINT("Failed to cleanup ip filter\n"); 266 | ret = KERN_FAILURE; 267 | } 268 | 269 | if(globalOSMallocTag) { 270 | OSMalloc_Tagfree(globalOSMallocTag); 271 | } 272 | 273 | DPRINT("iffilter_stop %d\n", ret); 274 | return KERN_SUCCESS; 275 | 276 | } 277 | 278 | /** 279 | * starts the kext 280 | * register SYSCTL and run each filters' setup function 281 | * 282 | * @param ki module info 283 | * @param d info 284 | * @returns 0 on success, error otherwise 285 | **/ 286 | kern_return_t iffilter_start(kmod_info_t * ki, void *d) 287 | { 288 | kern_return_t ret = KERN_SUCCESS; 289 | 290 | if(!globalOSMallocTag) { 291 | globalOSMallocTag = OSMalloc_Tagalloc(BID, OSMT_DEFAULT); 292 | } 293 | 294 | if(!globalOSMallocTag) { 295 | ret = KERN_FAILURE; 296 | DPRINT("Unable to allocate tag\n"); 297 | return ret; 298 | } 299 | 300 | // register sysctl oids 301 | sysctl_register_oid(&sysctl__net_netfil); 302 | 303 | sysctl_register_oid(&sysctl__net_netfil_interface); 304 | sysctl_register_oid(&sysctl__net_netfil_interface_list); 305 | sysctl_register_oid(&sysctl__net_netfil_interface_iobyte); 306 | sysctl_register_oid(&sysctl__net_netfil_interface_ibyte); 307 | sysctl_register_oid(&sysctl__net_netfil_interface_obyte); 308 | sysctl_register_oid(&sysctl__net_netfil_interface_status); 309 | 310 | sysctl_register_oid(&sysctl__net_netfil_socket); 311 | sysctl_register_oid(&sysctl__net_netfil_socket_pid); 312 | sysctl_register_oid(&sysctl__net_netfil_socket_iobyte); 313 | sysctl_register_oid(&sysctl__net_netfil_socket_ibyte); 314 | sysctl_register_oid(&sysctl__net_netfil_socket_obyte); 315 | sysctl_register_oid(&sysctl__net_netfil_socket_status); 316 | 317 | sysctl_register_oid(&sysctl__net_netfil_ip); 318 | sysctl_register_oid(&sysctl__net_netfil_ip_iobyte); 319 | sysctl_register_oid(&sysctl__net_netfil_ip_ibyte); 320 | sysctl_register_oid(&sysctl__net_netfil_ip_obyte); 321 | sysctl_register_oid(&sysctl__net_netfil_ip_addr); 322 | sysctl_register_oid(&sysctl__net_netfil_ip_status); 323 | 324 | // setup the interface filter 325 | if(interface_filter_setup() != 0) { 326 | DPRINT("Failed to setup interface filter\n"); 327 | ret |= KERN_FAILURE; 328 | } 329 | 330 | // setup socket filter 331 | if(socket_filter_setup() != 0) { 332 | DPRINT("Failed to setup socket filter\n"); 333 | ret |= KERN_FAILURE; 334 | } 335 | 336 | // setup socket filter 337 | if(ip_filter_setup() != 0) { 338 | DPRINT("Failed to setup ip filter\n"); 339 | ret |= KERN_FAILURE; 340 | } 341 | 342 | if(ret != KERN_SUCCESS) { 343 | cleanup(); 344 | } 345 | 346 | DPRINT("iffilter_start %d\n", ret); 347 | return ret; 348 | } 349 | 350 | /** 351 | * stops the kext and cleanups 352 | * 353 | * @param ki module info 354 | * @param d info 355 | * @returns 0 on success, error otherwise 356 | **/ 357 | kern_return_t iffilter_stop(kmod_info_t *ki, void *d) 358 | { 359 | kern_return_t ret = KERN_SUCCESS; 360 | 361 | ret = cleanup(); 362 | 363 | DPRINT("iffilter_stop %d\n", ret); 364 | return KERN_SUCCESS; 365 | } 366 | -------------------------------------------------------------------------------- /kext/kext.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1127B00A1E1ECF6900D778DC /* interface_filter.c in Sources */ = {isa = PBXBuildFile; fileRef = 1127B0081E1ECF6900D778DC /* interface_filter.c */; }; 11 | 1127B00B1E1ECF6900D778DC /* interface_filter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1127B0091E1ECF6900D778DC /* interface_filter.h */; }; 12 | 112B054D1E3F91E600869A9A /* ip_filter.c in Sources */ = {isa = PBXBuildFile; fileRef = 112B054B1E3F91E600869A9A /* ip_filter.c */; }; 13 | 112B054E1E3F91E600869A9A /* ip_filter.h in Headers */ = {isa = PBXBuildFile; fileRef = 112B054C1E3F91E600869A9A /* ip_filter.h */; }; 14 | 115617931E3673F500420549 /* socket_filter.c in Sources */ = {isa = PBXBuildFile; fileRef = 115617921E3673F500420549 /* socket_filter.c */; }; 15 | 11E1C3971E1D58B1008DDDC9 /* netfil.c in Sources */ = {isa = PBXBuildFile; fileRef = 11E1C3961E1D58B1008DDDC9 /* netfil.c */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | 1127B0081E1ECF6900D778DC /* interface_filter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = interface_filter.c; sourceTree = ""; }; 20 | 1127B0091E1ECF6900D778DC /* interface_filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interface_filter.h; sourceTree = ""; }; 21 | 1127B00C1E1ECF9A00D778DC /* common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = ""; }; 22 | 112B054B1E3F91E600869A9A /* ip_filter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ip_filter.c; sourceTree = ""; }; 23 | 112B054C1E3F91E600869A9A /* ip_filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ip_filter.h; sourceTree = ""; }; 24 | 115617911E3673E700420549 /* socket_filter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = socket_filter.h; sourceTree = ""; }; 25 | 115617921E3673F500420549 /* socket_filter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = socket_filter.c; sourceTree = ""; }; 26 | 118BC8EC1E56027800DC9BC7 /* errors.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = errors.h; sourceTree = ""; }; 27 | 11E1C3931E1D58B1008DDDC9 /* kext.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = kext.kext; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | 11E1C3961E1D58B1008DDDC9 /* netfil.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = netfil.c; sourceTree = ""; }; 29 | 11E1C3981E1D58B1008DDDC9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 30 | /* End PBXFileReference section */ 31 | 32 | /* Begin PBXFrameworksBuildPhase section */ 33 | 11E1C38F1E1D58B1008DDDC9 /* Frameworks */ = { 34 | isa = PBXFrameworksBuildPhase; 35 | buildActionMask = 2147483647; 36 | files = ( 37 | ); 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXFrameworksBuildPhase section */ 41 | 42 | /* Begin PBXGroup section */ 43 | 115617941E36740D00420549 /* include */ = { 44 | isa = PBXGroup; 45 | children = ( 46 | 1127B00C1E1ECF9A00D778DC /* common.h */, 47 | 118BC8EC1E56027800DC9BC7 /* errors.h */, 48 | 1127B0091E1ECF6900D778DC /* interface_filter.h */, 49 | 115617911E3673E700420549 /* socket_filter.h */, 50 | 112B054C1E3F91E600869A9A /* ip_filter.h */, 51 | ); 52 | name = include; 53 | sourceTree = ""; 54 | }; 55 | 11E1C3891E1D58B1008DDDC9 = { 56 | isa = PBXGroup; 57 | children = ( 58 | 11E1C3951E1D58B1008DDDC9 /* netfil */, 59 | 11E1C3941E1D58B1008DDDC9 /* Products */, 60 | ); 61 | sourceTree = ""; 62 | }; 63 | 11E1C3941E1D58B1008DDDC9 /* Products */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | 11E1C3931E1D58B1008DDDC9 /* kext.kext */, 67 | ); 68 | name = Products; 69 | sourceTree = ""; 70 | }; 71 | 11E1C3951E1D58B1008DDDC9 /* netfil */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 115617941E36740D00420549 /* include */, 75 | 11E1C3961E1D58B1008DDDC9 /* netfil.c */, 76 | 1127B0081E1ECF6900D778DC /* interface_filter.c */, 77 | 115617921E3673F500420549 /* socket_filter.c */, 78 | 112B054B1E3F91E600869A9A /* ip_filter.c */, 79 | 11E1C3981E1D58B1008DDDC9 /* Info.plist */, 80 | ); 81 | name = netfil; 82 | path = iffilter; 83 | sourceTree = ""; 84 | }; 85 | /* End PBXGroup section */ 86 | 87 | /* Begin PBXHeadersBuildPhase section */ 88 | 11E1C3901E1D58B1008DDDC9 /* Headers */ = { 89 | isa = PBXHeadersBuildPhase; 90 | buildActionMask = 2147483647; 91 | files = ( 92 | 1127B00B1E1ECF6900D778DC /* interface_filter.h in Headers */, 93 | 112B054E1E3F91E600869A9A /* ip_filter.h in Headers */, 94 | ); 95 | runOnlyForDeploymentPostprocessing = 0; 96 | }; 97 | /* End PBXHeadersBuildPhase section */ 98 | 99 | /* Begin PBXNativeTarget section */ 100 | 11E1C3921E1D58B1008DDDC9 /* kext */ = { 101 | isa = PBXNativeTarget; 102 | buildConfigurationList = 11E1C39B1E1D58B1008DDDC9 /* Build configuration list for PBXNativeTarget "kext" */; 103 | buildPhases = ( 104 | 11E1C38E1E1D58B1008DDDC9 /* Sources */, 105 | 11E1C38F1E1D58B1008DDDC9 /* Frameworks */, 106 | 11E1C3901E1D58B1008DDDC9 /* Headers */, 107 | 11E1C3911E1D58B1008DDDC9 /* Resources */, 108 | ); 109 | buildRules = ( 110 | ); 111 | dependencies = ( 112 | ); 113 | name = kext; 114 | productName = iffilter; 115 | productReference = 11E1C3931E1D58B1008DDDC9 /* kext.kext */; 116 | productType = "com.apple.product-type.kernel-extension"; 117 | }; 118 | /* End PBXNativeTarget section */ 119 | 120 | /* Begin PBXProject section */ 121 | 11E1C38A1E1D58B1008DDDC9 /* Project object */ = { 122 | isa = PBXProject; 123 | attributes = { 124 | LastUpgradeCheck = 0820; 125 | ORGANIZATIONNAME = ""; 126 | TargetAttributes = { 127 | 11E1C3921E1D58B1008DDDC9 = { 128 | CreatedOnToolsVersion = 8.1; 129 | ProvisioningStyle = Automatic; 130 | }; 131 | }; 132 | }; 133 | buildConfigurationList = 11E1C38D1E1D58B1008DDDC9 /* Build configuration list for PBXProject "kext" */; 134 | compatibilityVersion = "Xcode 3.2"; 135 | developmentRegion = English; 136 | hasScannedForEncodings = 0; 137 | knownRegions = ( 138 | en, 139 | ); 140 | mainGroup = 11E1C3891E1D58B1008DDDC9; 141 | productRefGroup = 11E1C3941E1D58B1008DDDC9 /* Products */; 142 | projectDirPath = ""; 143 | projectRoot = ""; 144 | targets = ( 145 | 11E1C3921E1D58B1008DDDC9 /* kext */, 146 | ); 147 | }; 148 | /* End PBXProject section */ 149 | 150 | /* Begin PBXResourcesBuildPhase section */ 151 | 11E1C3911E1D58B1008DDDC9 /* Resources */ = { 152 | isa = PBXResourcesBuildPhase; 153 | buildActionMask = 2147483647; 154 | files = ( 155 | ); 156 | runOnlyForDeploymentPostprocessing = 0; 157 | }; 158 | /* End PBXResourcesBuildPhase section */ 159 | 160 | /* Begin PBXSourcesBuildPhase section */ 161 | 11E1C38E1E1D58B1008DDDC9 /* Sources */ = { 162 | isa = PBXSourcesBuildPhase; 163 | buildActionMask = 2147483647; 164 | files = ( 165 | 11E1C3971E1D58B1008DDDC9 /* netfil.c in Sources */, 166 | 115617931E3673F500420549 /* socket_filter.c in Sources */, 167 | 112B054D1E3F91E600869A9A /* ip_filter.c in Sources */, 168 | 1127B00A1E1ECF6900D778DC /* interface_filter.c in Sources */, 169 | ); 170 | runOnlyForDeploymentPostprocessing = 0; 171 | }; 172 | /* End PBXSourcesBuildPhase section */ 173 | 174 | /* Begin XCBuildConfiguration section */ 175 | 11E1C3991E1D58B1008DDDC9 /* Debug */ = { 176 | isa = XCBuildConfiguration; 177 | buildSettings = { 178 | ALWAYS_SEARCH_USER_PATHS = NO; 179 | CLANG_ANALYZER_NONNULL = YES; 180 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 181 | CLANG_CXX_LIBRARY = "libc++"; 182 | CLANG_ENABLE_MODULES = YES; 183 | CLANG_ENABLE_OBJC_ARC = YES; 184 | CLANG_WARN_BOOL_CONVERSION = YES; 185 | CLANG_WARN_CONSTANT_CONVERSION = YES; 186 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 187 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 188 | CLANG_WARN_EMPTY_BODY = YES; 189 | CLANG_WARN_ENUM_CONVERSION = YES; 190 | CLANG_WARN_INFINITE_RECURSION = YES; 191 | CLANG_WARN_INT_CONVERSION = YES; 192 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 193 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 194 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 195 | CLANG_WARN_UNREACHABLE_CODE = YES; 196 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 197 | CODE_SIGN_IDENTITY = "-"; 198 | COPY_PHASE_STRIP = NO; 199 | DEBUG_INFORMATION_FORMAT = dwarf; 200 | ENABLE_STRICT_OBJC_MSGSEND = YES; 201 | ENABLE_TESTABILITY = YES; 202 | GCC_C_LANGUAGE_STANDARD = gnu99; 203 | GCC_DYNAMIC_NO_PIC = NO; 204 | GCC_NO_COMMON_BLOCKS = YES; 205 | GCC_OPTIMIZATION_LEVEL = 0; 206 | GCC_PREPROCESSOR_DEFINITIONS = ( 207 | "DEBUG=1", 208 | "$(inherited)", 209 | ); 210 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 211 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 212 | GCC_WARN_UNDECLARED_SELECTOR = YES; 213 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 214 | GCC_WARN_UNUSED_FUNCTION = YES; 215 | GCC_WARN_UNUSED_VARIABLE = YES; 216 | MACOSX_DEPLOYMENT_TARGET = 10.12; 217 | MTL_ENABLE_DEBUG_INFO = YES; 218 | ONLY_ACTIVE_ARCH = YES; 219 | SDKROOT = macosx; 220 | }; 221 | name = Debug; 222 | }; 223 | 11E1C39A1E1D58B1008DDDC9 /* Release */ = { 224 | isa = XCBuildConfiguration; 225 | buildSettings = { 226 | ALWAYS_SEARCH_USER_PATHS = NO; 227 | CLANG_ANALYZER_NONNULL = YES; 228 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 229 | CLANG_CXX_LIBRARY = "libc++"; 230 | CLANG_ENABLE_MODULES = YES; 231 | CLANG_ENABLE_OBJC_ARC = YES; 232 | CLANG_WARN_BOOL_CONVERSION = YES; 233 | CLANG_WARN_CONSTANT_CONVERSION = YES; 234 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 235 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 236 | CLANG_WARN_EMPTY_BODY = YES; 237 | CLANG_WARN_ENUM_CONVERSION = YES; 238 | CLANG_WARN_INFINITE_RECURSION = YES; 239 | CLANG_WARN_INT_CONVERSION = YES; 240 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 241 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 242 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 243 | CLANG_WARN_UNREACHABLE_CODE = YES; 244 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 245 | CODE_SIGN_IDENTITY = "-"; 246 | COPY_PHASE_STRIP = NO; 247 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 248 | ENABLE_NS_ASSERTIONS = NO; 249 | ENABLE_STRICT_OBJC_MSGSEND = YES; 250 | GCC_C_LANGUAGE_STANDARD = gnu99; 251 | GCC_NO_COMMON_BLOCKS = YES; 252 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 253 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 254 | GCC_WARN_UNDECLARED_SELECTOR = YES; 255 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 256 | GCC_WARN_UNUSED_FUNCTION = YES; 257 | GCC_WARN_UNUSED_VARIABLE = YES; 258 | MACOSX_DEPLOYMENT_TARGET = 10.12; 259 | MTL_ENABLE_DEBUG_INFO = NO; 260 | SDKROOT = macosx; 261 | }; 262 | name = Release; 263 | }; 264 | 11E1C39C1E1D58B1008DDDC9 /* Debug */ = { 265 | isa = XCBuildConfiguration; 266 | buildSettings = { 267 | GCC_PREPROCESSOR_DEFINITIONS = ( 268 | "DEBUG=1", 269 | "BID=\\\"$(PRODUCT_BUNDLE_IDENTIFIER)\\\"", 270 | "BNAME=\\\"$(PRODUCT_NAME)\\\"", 271 | ); 272 | HEADER_SEARCH_PATHS = ""; 273 | INFOPLIST_FILE = iffilter/Info.plist; 274 | MODULE_NAME = com.twodayslate.iffilter; 275 | MODULE_START = iffilter_start; 276 | MODULE_STOP = iffilter_stop; 277 | MODULE_VERSION = 1.0.0d1; 278 | PRODUCT_BUNDLE_IDENTIFIER = com.company.netfil; 279 | PRODUCT_NAME = "$(TARGET_NAME)"; 280 | USER_HEADER_SEARCH_PATHS = ""; 281 | WRAPPER_EXTENSION = kext; 282 | }; 283 | name = Debug; 284 | }; 285 | 11E1C39D1E1D58B1008DDDC9 /* Release */ = { 286 | isa = XCBuildConfiguration; 287 | buildSettings = { 288 | GCC_PREPROCESSOR_DEFINITIONS = ( 289 | "BID=\\\"$(PRODUCT_BUNDLE_IDENTIFIER)\\\"", 290 | "BNAME=\\\"$(PRODUCT_NAME)\\\"", 291 | ); 292 | HEADER_SEARCH_PATHS = ""; 293 | INFOPLIST_FILE = iffilter/Info.plist; 294 | MODULE_NAME = com.twodayslate.iffilter; 295 | MODULE_START = iffilter_start; 296 | MODULE_STOP = iffilter_stop; 297 | MODULE_VERSION = 1.0.0d1; 298 | PRODUCT_BUNDLE_IDENTIFIER = com.company.netfil; 299 | PRODUCT_NAME = "$(TARGET_NAME)"; 300 | USER_HEADER_SEARCH_PATHS = ""; 301 | WRAPPER_EXTENSION = kext; 302 | }; 303 | name = Release; 304 | }; 305 | /* End XCBuildConfiguration section */ 306 | 307 | /* Begin XCConfigurationList section */ 308 | 11E1C38D1E1D58B1008DDDC9 /* Build configuration list for PBXProject "kext" */ = { 309 | isa = XCConfigurationList; 310 | buildConfigurations = ( 311 | 11E1C3991E1D58B1008DDDC9 /* Debug */, 312 | 11E1C39A1E1D58B1008DDDC9 /* Release */, 313 | ); 314 | defaultConfigurationIsVisible = 0; 315 | defaultConfigurationName = Release; 316 | }; 317 | 11E1C39B1E1D58B1008DDDC9 /* Build configuration list for PBXNativeTarget "kext" */ = { 318 | isa = XCConfigurationList; 319 | buildConfigurations = ( 320 | 11E1C39C1E1D58B1008DDDC9 /* Debug */, 321 | 11E1C39D1E1D58B1008DDDC9 /* Release */, 322 | ); 323 | defaultConfigurationIsVisible = 0; 324 | defaultConfigurationName = Release; 325 | }; 326 | /* End XCConfigurationList section */ 327 | }; 328 | rootObject = 11E1C38A1E1D58B1008DDDC9 /* Project object */; 329 | } 330 | -------------------------------------------------------------------------------- /menubar/t2/InterfaceViewController.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import AppKit 3 | 4 | class InterfaceViewController : NSViewController { 5 | 6 | // Might want to provide a list of interfaces? 7 | // http://stackoverflow.com/questions/4367927/get-a-list-of-all-available-network-interfaces-en0-en1-en2-etc-with-cocoa 8 | 9 | var button : NSButton? 10 | var mainStackView : NSStackView? 11 | var all : NSTextField? 12 | var interfaceTextFields = [TSTextField]() 13 | var insideTable : NSStackView? 14 | 15 | var iByte : NSTextField? 16 | var oByte : NSTextField? 17 | var ioByte : NSTextField? 18 | 19 | 20 | override func loadView() { 21 | view = NSStackView(frame: NSRect(x: 0, y: 0, width: 500, height: 0)) 22 | (view as! NSStackView).orientation = NSUserInterfaceLayoutOrientation.vertical 23 | (view as! NSStackView).spacing = CGFloat(PADDING) 24 | let titleBarSize = NSWindow.frameRect(forContentRect: self.view.frame, styleMask: NSWindowStyleMask.titled).height 25 | (view as! NSStackView).edgeInsets = EdgeInsets(top: titleBarSize, left: PADDING, bottom: PADDING, right: PADDING) 26 | //(view as! NSStackView).translatesAutoresizingMaskIntoConstraints = false 27 | 28 | //Interface.shared.isActive = Interface.activity.inactive 29 | 30 | //self.addObserver(Interface.isActive, forKeyPath: "status", options: 0, context: nil) 31 | 32 | //Interface.shared 33 | 34 | } 35 | 36 | override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 37 | 38 | //super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) 39 | if(keyPath == "isActive") { 40 | statusChange() 41 | print("\(keyPath) did change here!", Interface.shared.isActive) 42 | } 43 | } 44 | 45 | override func viewDidLoad() { 46 | mainStackView = NSStackView() 47 | mainStackView?.orientation = NSUserInterfaceLayoutOrientation.vertical 48 | mainStackView?.alignment = NSLayoutAttribute.left 49 | mainStackView?.detachesHiddenViews = true 50 | mainStackView?.translatesAutoresizingMaskIntoConstraints = false 51 | //mainStackView?.frame.size = NSSize(width: 500, height: 50) 52 | //mainStackView?.setHuggingPriority(NSLayoutPriorityWindowSizeStayPut , for: NSLayoutConstraintOrientation.vertical) 53 | //mainStackView?.distribution = NSStackViewDistribution.fill 54 | 55 | all = NSTextField(string: "Filter All Interfaces") 56 | all?.alignment = NSTextAlignment.center 57 | all?.tag = -666; 58 | all?.alphaValue = 0.7 59 | all?.isBordered = false 60 | all?.isEditable = false 61 | all?.isSelectable = false 62 | all?.backgroundColor = NSColor.clear 63 | //mainStackView?.addArrangedSubview(all!) 64 | 65 | let table = NSScrollView(frame: NSRect(x: 0, y: 0, width: 500, height: 100)) 66 | table.frame.size.height = 100 67 | insideTable = NSStackView(frame: table.frame) 68 | insideTable?.orientation = NSUserInterfaceLayoutOrientation.vertical 69 | //insideTable.alignment = NSLayoutAttribute.left 70 | insideTable?.translatesAutoresizingMaskIntoConstraints = false 71 | insideTable?.detachesHiddenViews = true 72 | // for item in interfaceList { 73 | // let t = NSTextField(string: item) 74 | // t.placeholderString = "Interface Name" 75 | // insideTable?.addArrangedSubview(t) 76 | // } 77 | //table.documentView = insideTable 78 | //table.hasVerticalScroller = true 79 | //table.autohidesScrollers = true 80 | //table.translatesAutoresizingMaskIntoConstraints = false 81 | table.autoresizingMask = NSAutoresizingMaskOptions.viewWidthSizable 82 | table.contentView = TSClipView(frame: table.contentView.frame) 83 | table.documentView = insideTable 84 | 85 | table.borderType = NSBorderType.bezelBorder 86 | insideTable?.addArrangedSubview(all!) 87 | 88 | let eq = NSLayoutConstraint(item: table, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: insideTable!, attribute: NSLayoutAttribute.width, multiplier: 1.0, constant: 0) 89 | table.addConstraint(eq) 90 | 91 | mainStackView?.addArrangedSubview(table) 92 | 93 | let sc = NSSegmentedControl(images: [NSImage(named: NSImageNameAddTemplate)!, NSImage(named: NSImageNameRemoveTemplate)!, ], trackingMode: NSSegmentSwitchTracking.selectOne, target: self, action: #selector(self.didHit)) 94 | sc.setEnabled(false, forSegment: 1) 95 | mainStackView?.addArrangedSubview(sc) 96 | 97 | 98 | button = NSButton(title: "Go!", target: self, action: #selector(buttonPress)) 99 | 100 | let iByteName = NSTextField(string: "iByte:") 101 | iByteName.isBordered = false 102 | iByteName.isEditable = false 103 | iByteName.isSelectable = false 104 | iByteName.backgroundColor = NSColor.clear 105 | 106 | let iByteLabel = NSTextField(string: "bytes") 107 | iByteLabel.isBordered = false 108 | iByteLabel.isEditable = false 109 | iByteLabel.isSelectable = false 110 | iByteLabel.alphaValue = 0.7 111 | iByteLabel.backgroundColor = NSColor.clear 112 | 113 | iByte = NSTextField(string: String(Interface.shared.iByte)) 114 | iByte?.placeholderString = "0" 115 | iByte?.alignment = NSTextAlignment.right 116 | 117 | let iByteStack = NSStackView(views: [iByteName, iByte!, iByteLabel]) 118 | iByteStack.orientation = NSUserInterfaceLayoutOrientation.horizontal 119 | 120 | let oByteName = NSTextField(string: "oByte:") 121 | oByteName.isBordered = false 122 | oByteName.isEditable = false 123 | oByteName.isSelectable = false 124 | oByteName.backgroundColor = NSColor.clear 125 | 126 | let oByteLabel = NSTextField(string: "bytes") 127 | oByteLabel.isBordered = false 128 | oByteLabel.isEditable = false 129 | oByteLabel.isSelectable = false 130 | oByteLabel.alphaValue = 0.7 131 | oByteLabel.backgroundColor = NSColor.clear 132 | 133 | oByte = NSTextField(string: String(Interface.shared.oByte)) 134 | oByte?.placeholderString = "0" 135 | oByte?.alignment = NSTextAlignment.right 136 | 137 | let oByteStack = NSStackView(views: [oByteName, oByte!, oByteLabel]) 138 | oByteStack.orientation = NSUserInterfaceLayoutOrientation.horizontal 139 | 140 | let ioByteName = NSTextField(string: "ioByte:") 141 | ioByteName.isBordered = false 142 | ioByteName.isEditable = false 143 | ioByteName.isSelectable = false 144 | ioByteName.backgroundColor = NSColor.clear 145 | 146 | let ioByteLabel = NSTextField(string: "bytes") 147 | ioByteLabel.isBordered = false 148 | ioByteLabel.isEditable = false 149 | ioByteLabel.isSelectable = false 150 | ioByteLabel.wantsLayer = true // to enable transparency 151 | ioByteLabel.alphaValue = 0.7 152 | ioByteLabel.backgroundColor = NSColor.clear 153 | 154 | ioByte = TSTextField(string: String(Interface.shared.ioByte)) 155 | ioByte?.placeholderString = "0" 156 | ioByte?.alignment = NSTextAlignment.right 157 | 158 | let ioByteStack = NSStackView(views: [ioByteName, ioByte!, ioByteLabel]) 159 | ioByteStack.orientation = NSUserInterfaceLayoutOrientation.horizontal 160 | //ioByteStack.alignment = NSLayoutAttribute.right 161 | 162 | //let parentStackView = NSStackView(views: [titleStackView, iByteStack, oByteStack, ioByteStack, mainStackView!, button!]) 163 | //parentStackView.orientation = NSUserInterfaceLayoutOrientation.vertical 164 | //parentStackView.frame.size.height = 20 165 | //parentStackView.frame.size.width = 200; 166 | //self.view = parentStackView 167 | (view as! NSStackView).addArrangedSubview(iByteStack) 168 | (view as! NSStackView).addArrangedSubview(oByteStack) 169 | (view as! NSStackView).addArrangedSubview(ioByteStack) 170 | (view as! NSStackView).addArrangedSubview(mainStackView!) 171 | (view as! NSStackView).addArrangedSubview(button!) 172 | 173 | let equal = NSLayoutConstraint(item: table.contentView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal , toItem: mainStackView!, attribute: NSLayoutAttribute.height, multiplier: 0.0, constant: 100.0) 174 | mainStackView?.addConstraint(equal) 175 | 176 | let equal2 = NSLayoutConstraint(item: all!, attribute: NSLayoutAttribute.width , relatedBy: NSLayoutRelation.equal , toItem: mainStackView!, attribute: NSLayoutAttribute.width, multiplier: 1.0, constant: 0.0) 177 | mainStackView?.addConstraint(equal2) 178 | 179 | let equal3 = NSLayoutConstraint(item: mainStackView!, attribute: NSLayoutAttribute.width , relatedBy: NSLayoutRelation.equal , toItem: self.view, attribute: NSLayoutAttribute.width, multiplier: 0.0, constant: self.view.frame.width - PADDING * 2) 180 | self.view.addConstraint(equal3) 181 | 182 | Interface.shared.addObserver(self, forKeyPath: "isActive", options: [NSKeyValueObservingOptions.initial, NSKeyValueObservingOptions.new], context: nil) 183 | 184 | Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(checkStatus), userInfo: nil, repeats: true) 185 | } 186 | 187 | func buttonPress() { 188 | switch(Interface.shared.isActive) { 189 | case .active: 190 | Interface.shared.isActive = Interface.activity.inactive 191 | break 192 | case .inactive: 193 | var l = [String]() 194 | for i in interfaceTextFields { 195 | if(!i.stringValue.isEmpty) { 196 | l.append(i.stringValue) 197 | } 198 | } 199 | Interface.shared.list = l 200 | Interface.shared.iByte = CInt(Int((iByte?.stringValue)!)!) 201 | Interface.shared.oByte = CInt(Int((oByte?.stringValue)!)!) 202 | Interface.shared.ioByte = CInt(Int((ioByte?.stringValue)!)!) 203 | Interface.shared.isActive = Interface.activity.active 204 | break 205 | default: 206 | break 207 | } 208 | statusChange() 209 | } 210 | 211 | func statusChange() { 212 | let s = Interface.shared.isActive 213 | lastStatus = s 214 | switch(Interface.shared.isActive) { 215 | case .active: 216 | button?.title = "Stop" 217 | button?.isEnabled = true 218 | break 219 | case .inactive: 220 | button?.title = "Filter" 221 | button?.isEnabled = true 222 | break 223 | default: 224 | button?.title = "Filter" 225 | button?.isEnabled = false 226 | } 227 | } 228 | 229 | var lastStatus : Interface.activity = Interface.activity.unknown 230 | func checkStatus() { 231 | 232 | // This is necessary cause our KVO only detects changes 233 | // that we make, not that the kernel makes, or other 234 | // external programs 235 | 236 | if Interface.shared.isActive != lastStatus { 237 | statusChange() 238 | } 239 | } 240 | 241 | func didHit(_ sender : NSSegmentedControl) { 242 | print("did hit", sender.selectedSegment) 243 | if(sender.selectedSegment == 0) { 244 | self.addRow(sender) 245 | } else { 246 | self.removeRow(sender) 247 | } 248 | sender.setSelected(false, forSegment: sender.selectedSegment) 249 | } 250 | 251 | func removeRow(_ sender : NSSegmentedControl) { 252 | 253 | var didFind = false 254 | for (index, textField) in interfaceTextFields.enumerated() { 255 | if textField.isEditing { 256 | didFind = true 257 | print(textField.stringValue, "is first responder") 258 | textField.removeFromSuperview() 259 | interfaceTextFields.remove(at: index) 260 | 261 | if(interfaceTextFields.count > 0) { 262 | if(interfaceTextFields.count > index) { 263 | self.view.window?.makeFirstResponder(interfaceTextFields[index]) 264 | } else { 265 | self.view.window?.makeFirstResponder(interfaceTextFields[max(index-1, 0)]) 266 | } 267 | } 268 | break 269 | } 270 | } 271 | 272 | if(!didFind) { 273 | sender.setEnabled(false, forSegment: 1) 274 | } 275 | 276 | if(interfaceTextFields.count <= 0) { 277 | all?.isHidden = false 278 | sender.setEnabled(false, forSegment: 1) 279 | } 280 | } 281 | 282 | var firstResponder : NSResponder? { 283 | get { 284 | return self.view.window?.firstResponder 285 | } 286 | } 287 | 288 | func addRow(_ sender : NSSegmentedControl) { 289 | all?.isHidden = true 290 | //sender.setEnabled(true, forSegment: 1) 291 | 292 | let removeButton = NSButton(image: NSImage(named: NSImageNameStopProgressFreestandingTemplate)!, target: self, action: #selector(self.removeRow)) 293 | removeButton.imagePosition = NSCellImagePosition.imageOnly 294 | removeButton.isBordered = false 295 | 296 | let ifn = TSTextField() 297 | ifn.placeholderString = "Interface name" 298 | ifn.isSelectable = true 299 | ifn.segmentControl = sender 300 | interfaceTextFields.append(ifn) 301 | 302 | let row = NSStackView() 303 | row.addArrangedSubview(ifn) 304 | //row.addArrangedSubview(removeButton) 305 | //let row = NSStackView(views: [ifn, removeButton]) 306 | //row.frame.size.width = WIDTH 307 | row.orientation = NSUserInterfaceLayoutOrientation.horizontal 308 | //row.alignment = NSLayoutAttribute.right 309 | 310 | // let sss = NSLayoutConstraint(item: row, attribute: NSLayoutAttribute.width , relatedBy: NSLayoutRelation.equal , toItem: ifn, attribute: NSLayoutAttribute.width, multiplier: 0.5, constant: -60 ) 311 | // row.addConstraint(sss) 312 | 313 | 314 | //removeButton.tag = max((mainStackView?.arrangedSubviews.count)!-1, 0) 315 | insideTable?.addArrangedSubview(ifn) 316 | //self.view.window?.makeFirstResponder(ifn) 317 | ifn.selectText(self) 318 | 319 | // if(self.view.window?.makeFirstResponder(ifn))! { 320 | // ifn.isEditing = true 321 | // sender.setEnabled(true, forSegment: 1) 322 | // } 323 | // let equal = NSLayoutConstraint(item: insideTable!, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal , toItem: row, attribute: NSLayoutAttribute.width, multiplier: 1.0, constant: 0.0) 324 | // insideTable?.addConstraint(equal) 325 | 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /kext/iffilter/interface_filter.c: -------------------------------------------------------------------------------- 1 | #include "interface_filter.h" 2 | 3 | /** interfaces to filter */ 4 | static ifnet_t *interfaces = NULL; 5 | /** active filters of interfaces */ 6 | static struct filters *filters = NULL; 7 | /** number of interfaces to filter */ 8 | static u_int32_t ifCount = 0; 9 | /** number of interfaces currenly with a filter */ 10 | static u_int32_t realIfCount = 0; 11 | /** user defined interface list */ 12 | static struct array *userInterfaces = NULL; 13 | 14 | errno_t interface_filter_setup() { 15 | interfaces = NULL; 16 | user_interface_io_byte_limit = 0; 17 | user_interface_in_byte_limit = 0; 18 | user_interface_out_byte_limit = 0; 19 | interface_status = 0; 20 | return 0; 21 | } 22 | 23 | errno_t interface_filter_cleanup() { 24 | errno_t ret = 0; 25 | 26 | ret = interface_filter_stop(); 27 | 28 | return ret; 29 | } 30 | 31 | errno_t interface_filter_start() { 32 | 33 | if(interfaces != NULL) { 34 | // this was already called so don't do it again! 35 | DPRINT("WARNING! You have to stop, before you can start again!"); 36 | return -1; 37 | } 38 | 39 | errno_t ret = 0; 40 | 41 | ifCount = 0; 42 | 43 | if(userInterfaces) { 44 | #ifdef DEBUG 45 | DPRINT("userInteface count %d\n", userInterfaces->size); 46 | #endif 47 | if(userInterfaces->size > 0) { 48 | interfaces = OSMalloc(sizeof(interfaces) * userInterfaces->size, globalOSMallocTag); 49 | if(interfaces == NULL) { 50 | DPRINT("unable to malloc interfaces\n"); 51 | return -1; 52 | } 53 | for(int i = 0; i < userInterfaces->size; i++) { 54 | ifnet_t p_ifnet; 55 | errno_t err = ifnet_find_by_name(userInterfaces->values[i], &p_ifnet); 56 | if(err) { 57 | DPRINT("%s is not a valid interface\n", userInterfaces->values[i]); 58 | continue; 59 | } 60 | interfaces[ifCount++] = p_ifnet; 61 | } 62 | } 63 | } 64 | 65 | DPRINT("ifCount = %d\n", ifCount); 66 | 67 | if(ifCount <= 0){ 68 | if(interfaces) { // userInterfaces was not null but no valid interfaces... so have to free 69 | OSFree(interfaces, sizeof(interfaces) * userInterfaces->size, globalOSMallocTag); 70 | } 71 | ret = ifnet_list_get(IFNET_FAMILY_ANY, &interfaces, &ifCount); 72 | if(ret != 0) { 73 | return -1; 74 | } 75 | DPRINT("got list of %d attached interfaces \n", ifCount); 76 | 77 | } 78 | 79 | if(ifCount > 0) { 80 | filters = OSMalloc(sizeof(struct filters) * ifCount, globalOSMallocTag); 81 | if(filters == NULL) { 82 | ifnet_list_free(interfaces); 83 | DPRINT("malloc error\n"); 84 | return -2; 85 | } 86 | } 87 | 88 | DPRINT("malloc success\n"); 89 | 90 | for(int i = 0; i < ifCount; i++) { 91 | const char *name = ifnet_name(interfaces[i]); 92 | 93 | DPRINT("at %s %d\n", name, i); 94 | 95 | if(strncmp(name, "lo", 2) == 0) 96 | continue; 97 | 98 | filters[realIfCount].id = realIfCount; 99 | filters[realIfCount].filter.iff_cookie = (void *) &(filters[realIfCount]); 100 | filters[realIfCount].filter.iff_name = "iffilter"; 101 | filters[realIfCount].filter.iff_output = out_handler; 102 | filters[realIfCount].filter.iff_input = in_handler; 103 | filters[realIfCount].filter.iff_protocol = 0; 104 | filters[realIfCount].filter.iff_event = event_handler; 105 | filters[realIfCount].filter.iff_ioctl = ioctl_handler; 106 | filters[realIfCount].filter.iff_detached = NULL; 107 | 108 | struct timespec tsp; 109 | getnanotime(&tsp); 110 | filters[realIfCount].reset = tsp.tv_sec; 111 | filters[realIfCount].bytes_in_since_reset = 0; 112 | filters[realIfCount].bytes_out_since_reset = 0; 113 | 114 | ret = iflt_attach(interfaces[i], &(filters[realIfCount].filter), &(filters[realIfCount].ref)); 115 | if(ret == 0) { 116 | DPRINT("an interface registered\n"); 117 | realIfCount++; 118 | } 119 | } 120 | 121 | return ret; 122 | } 123 | 124 | errno_t interface_filter_stop() { 125 | 126 | if(interfaces) ifnet_list_free(interfaces); 127 | 128 | if(filters) { 129 | for(int i = 0; i < realIfCount; i++) { 130 | if(filters[i].ref != NULL) { 131 | iflt_detach(filters[i].ref); 132 | } 133 | } 134 | OSFree(filters, sizeof(struct filters) * ifCount, globalOSMallocTag); 135 | } 136 | 137 | freeUserInterfaces(); 138 | 139 | filters = NULL; 140 | interfaces = NULL; 141 | ifCount = 0; 142 | realIfCount = 0; 143 | 144 | interface_status = 0; 145 | 146 | return 0; 147 | } 148 | 149 | errno_t ioctl_handler(void *cookie, ifnet_t interface, protocol_family_t protocol, unsigned long ioctl_cmd, void *ioctl_arg) { 150 | #ifdef DEBUG 151 | const char *name = ifnet_name(interface); 152 | u_int32_t index = ifnet_index(interface); 153 | DPRINT("filtering ioctl for %s%d\n", name, index); 154 | #endif 155 | return 0; 156 | } 157 | 158 | void event_handler(void *cookie, ifnet_t interface, protocol_family_t protocol, const struct kev_msg *event_msg) { 159 | #ifdef DEBUG 160 | const char *name = ifnet_name(interface); 161 | u_int32_t index = ifnet_index(interface); 162 | DPRINT("%s%d received event [vendor_code = %u, kev_class = %u, kev_subclass = %u, event_code = %u]\n", name, index, event_msg->vendor_code, event_msg->kev_class, event_msg->kev_subclass, event_msg->event_code); 163 | #endif 164 | } 165 | 166 | errno_t out_handler(void *cookie, ifnet_t interface, protocol_family_t protocol, mbuf_t *data) { 167 | 168 | struct filters *filter = (struct filters *) cookie; 169 | filter->bytes_out_since_reset += mbuf_len(*data); 170 | 171 | 172 | #ifdef DEBUG 173 | const char *name = ifnet_name(interface); 174 | u_int32_t index = ifnet_index(interface); 175 | DPRINT("filtering out for %s%d\n", name, index); 176 | DPRINT("bytes_out_since_reset: %llu\n",filter->bytes_out_since_reset); 177 | #endif 178 | 179 | if(user_interface_out_byte_limit != 0 && filter->bytes_out_since_reset > user_interface_out_byte_limit) { 180 | return !EJUSTRETURN; 181 | } 182 | 183 | if(user_interface_io_byte_limit != 0 && (filter->bytes_in_since_reset + filter->bytes_out_since_reset) > user_interface_io_byte_limit) { 184 | return !EJUSTRETURN; 185 | } 186 | 187 | return 0; 188 | } 189 | 190 | errno_t in_handler(void *cookie, ifnet_t interface, protocol_family_t protocol, mbuf_t *data, char **frame_ptr) { 191 | 192 | DPRINT("self iface pid %d\n", proc_selfpid()); 193 | DPRINT("self iface uid %d\n", kauth_getuid() ); 194 | 195 | struct filters *filter = (struct filters *) cookie; 196 | filter->bytes_in_since_reset += mbuf_len(*data); 197 | 198 | #ifdef DEBUG 199 | const char *name = ifnet_name(interface); 200 | u_int8_t type = ifnet_type(interface); 201 | u_int32_t mtu = ifnet_mtu(interface); // maximum transmission unit 202 | u_int32_t unit = ifnet_unit(interface); // unit number 203 | u_int32_t index = ifnet_index(interface); // This index value will match the index you would find in a sockaddr_dl or using if_nametoindex or if_indextoname in user space. The value of the interface index is undefined for an interface that is not currently attached. 204 | 205 | DPRINT("filtering in for %s with type %d; mtu %d; unit %d; index %d\n", name, type, mtu, unit, index); 206 | DPRINT("protocol: %d\n", protocol); 207 | 208 | struct ifnet_stats_param stats; 209 | ifnet_stat(interface, &stats); 210 | DPRINT("bytes_in %llu; bytes_out %llu; packets in %llu; packets_out %llu\n", stats.bytes_in, stats.bytes_out, stats.packets_in, stats.packets_out); 211 | DPRINT("bytes_in_since_reset: %llu\n", filter->bytes_in_since_reset); 212 | #endif 213 | 214 | if(user_interface_in_byte_limit != 0 && filter->bytes_in_since_reset > user_interface_in_byte_limit) { 215 | return !EJUSTRETURN; 216 | } 217 | 218 | if(user_interface_io_byte_limit != 0 && (filter->bytes_in_since_reset + filter->bytes_out_since_reset) > user_interface_io_byte_limit) { 219 | return !EJUSTRETURN; 220 | } 221 | 222 | return 0; 223 | } 224 | 225 | int sysctl_iff_status_handler SYSCTL_HANDLER_ARGS { 226 | DPRINT("inside interface %s (%d)\n", oidp->oid_name, oidp->oid_number); 227 | 228 | int old = interface_status; 229 | 230 | int error = sysctl_handle_int(oidp, arg1, arg2, req); 231 | 232 | if (!error && req->newptr) { // write request 233 | DPRINT("write for %s %d\n", oidp->oid_name, error); 234 | DPRINT("old %d new %d\n", old, interface_status); 235 | 236 | if(old != interface_status) { 237 | DPRINT("things are different\n"); 238 | if(interface_status == 1) { 239 | if(interface_filter_start() != 0) { 240 | // some error, cleanup and set status to 0 241 | interface_filter_stop(); 242 | interface_status = 0; 243 | } 244 | } else { 245 | interface_status = 0; 246 | interface_filter_stop(); 247 | } 248 | } 249 | } else if (req->newptr) { 250 | DPRINT("write with error %d for %s\n", error, oidp->oid_name); 251 | /* Something was wrong with the write request */ 252 | /* Do something here if you feel like it.... */ 253 | } else { 254 | DPRINT("read for interface %s: %d\n", oidp->oid_name, interface_status); 255 | error = 0; 256 | } 257 | 258 | return error; 259 | } 260 | 261 | int sysctl_iff_interfaces_handler SYSCTL_HANDLER_ARGS { 262 | DPRINT("inside interface.%s (%d)\n", oidp->oid_name, oidp->oid_number); 263 | 264 | uint64_t addr; 265 | int error = SYSCTL_IN(req, &addr, sizeof(addr)); 266 | 267 | if (!error && req->newptr && req->newlen >= sizeof(struct array)) { 268 | struct array r; 269 | 270 | error = copyin(req->newptr, &r, sizeof(struct array)); 271 | 272 | if(error == 0 && r.size > 0) { 273 | /* We have a new value stored in the standard location.*/ 274 | /* Do with it as you see fit here. */ 275 | DPRINT("sysctl %s: stored\n", oidp->oid_name); 276 | 277 | DPRINT("string %p size %d", r.values, r.size); 278 | 279 | freeUserInterfaces(); 280 | 281 | userInterfaces = OSMalloc(sizeof(userInterfaces), globalOSMallocTag); 282 | if(userInterfaces == NULL) { 283 | DPRINT("unable to allocate userInterfaces\n"); 284 | return -1; 285 | } 286 | 287 | char **ns = OSMalloc(r.size * sizeof(void**), globalOSMallocTag); 288 | if(ns == NULL) { 289 | OSFree(userInterfaces, sizeof(userInterfaces), globalOSMallocTag); 290 | userInterfaces = NULL; 291 | DPRINT("Unable to allocate memory for ns\n"); 292 | return -1; 293 | } 294 | int count = 0; 295 | 296 | userInterfaces->size = r.size; 297 | userInterfaces->values = OSMalloc(userInterfaces->size * sizeof(userInterfaces->values), globalOSMallocTag); 298 | if(userInterfaces->values == NULL) { 299 | OSFree(ns, r.size * sizeof(void**), globalOSMallocTag); 300 | OSFree(userInterfaces, sizeof(userInterfaces), globalOSMallocTag); 301 | userInterfaces = NULL; 302 | DPRINT("unable to allocate userInterfaces->values\n"); 303 | return -1; 304 | } 305 | 306 | error = copyin((user_addr_t) r.values, ns, r.size*sizeof(void**)); 307 | if(error == 0) { 308 | DPRINT("string names %p %p", ns, ns[0]); 309 | 310 | for(int i = 0; i < r.size; i++) { 311 | char *n = OSMalloc(MAXCOMLEN + 1, globalOSMallocTag); 312 | if(n != NULL) { 313 | size_t copied; 314 | error = copyinstr((user_addr_t) ns[i], n, MAXCOMLEN, &copied); 315 | 316 | if(error == 0) { 317 | DPRINT("string copied %zu bytes", copied); 318 | DPRINT("string value = %s\n", n); 319 | ifnet_t p_ifnet; 320 | errno_t err = ifnet_find_by_name(n, &p_ifnet); 321 | if(err) { 322 | DPRINT("%s is not a valid interface\n", n); 323 | } 324 | userInterfaces->values[count++] = n; 325 | } else if(error == ENAMETOOLONG) { 326 | DPRINT("string input was too long!"); 327 | } 328 | } else { 329 | DPRINT("unable to allocate memory for a name for userinterfaces; skipping\n"); 330 | } 331 | } 332 | } 333 | 334 | if(ns) OSFree(ns, r.size * sizeof(void**), globalOSMallocTag); 335 | } 336 | } else if (req->newptr) { 337 | /* Something was wrong with the write request */ 338 | /* Do something here if you feel like it.... */ 339 | DPRINT("sysctl %s: write/error\n", oidp->oid_name); 340 | } else { 341 | /* Read request. Always return 763, just for grins. */ 342 | DPRINT("sysctl interface %s: read\n", oidp->oid_name); 343 | DPRINT("old pts %llu old len %zu", req->oldptr, req->oldlen); 344 | if(req->oldptr && req->oldlen > sizeof(int)) { 345 | // has a pointer so put data structure in it 346 | struct array rar; 347 | 348 | error = copyin(req->oldptr, &rar, sizeof(struct array)); 349 | 350 | DPRINT("rar %p\n", &rar); 351 | 352 | // TODO: better checks here for the correct size 353 | 354 | if(interfaces) { 355 | 356 | if(req->oldlen < sizeof(ifnet_t)) { 357 | return SYSCTL_OUT(req, NULL, 0); 358 | } 359 | 360 | copyout(&ifCount, (user_addr_t) rar.size, sizeof(ifCount)); 361 | 362 | char **ns = OSMalloc(rar.size * sizeof(void**), globalOSMallocTag); 363 | error = copyin((user_addr_t) rar.values, ns, rar.size*sizeof(void**)); 364 | 365 | for(int i = 0; i < userInterfaces->size; i++) { 366 | const char *name = ifnet_name(interfaces[i]); 367 | size_t wrote = 0; 368 | DPRINT("%d: %p\n", i, ns[i]); 369 | copyoutstr(name, (user_addr_t) ns[i], strnlen(name, MAXCOMLEN), &wrote); 370 | } 371 | 372 | OSFree(ns, rar.size * sizeof(void**), globalOSMallocTag); 373 | 374 | } else if(userInterfaces) { 375 | 376 | if(req->oldlen < sizeof(struct array) + userInterfaces->size * sizeof(void**)) { 377 | return SYSCTL_OUT(req, NULL, 0); 378 | } 379 | 380 | copyout(&(userInterfaces->size), (user_addr_t) rar.size, sizeof(userInterfaces->size)); 381 | 382 | char **ns = OSMalloc(rar.size * sizeof(void**), globalOSMallocTag); 383 | error = copyin((user_addr_t) rar.values, ns, rar.size*sizeof(void**)); 384 | 385 | for(int i = 0; i < userInterfaces->size; i++) { 386 | size_t wrote = 0; 387 | DPRINT("%d: %p\n", i, ns[i]); 388 | copyoutstr(userInterfaces->values[i], (user_addr_t) ns[i], strnlen(userInterfaces->values[i], MAXCOMLEN), &wrote); 389 | } 390 | 391 | OSFree(ns, rar.size * sizeof(void**), globalOSMallocTag); 392 | } else { 393 | error = SYSCTL_OUT(req, NULL, 0); 394 | } 395 | } else if(req->oldptr && req->oldlen == sizeof(int)){ 396 | // no pointer so just return the size 397 | DPRINT("nah inside here 2\n"); 398 | 399 | int val = 0; 400 | if(interfaces) { 401 | val = ifCount; 402 | } else if (userInterfaces) { 403 | val = userInterfaces->size; 404 | } 405 | SYSCTL_OUT(req, &val, sizeof(int)); 406 | } 407 | 408 | 409 | 410 | } 411 | return error; 412 | } 413 | 414 | int freeUserInterfaces() { 415 | if(userInterfaces != NULL) { 416 | if(userInterfaces->size > 0) { 417 | for(int i = 0; i < userInterfaces->size; i++) { 418 | if(userInterfaces->values[i]) OSFree(userInterfaces->values[i], MAXCOMLEN+1, globalOSMallocTag); 419 | } 420 | OSFree(userInterfaces->values, sizeof(userInterfaces->values) * userInterfaces->size, globalOSMallocTag); 421 | } 422 | 423 | userInterfaces->size = 0; 424 | 425 | OSFree(userInterfaces, sizeof(userInterfaces), globalOSMallocTag); 426 | 427 | userInterfaces = NULL; 428 | } 429 | 430 | return 0; 431 | } 432 | 433 | -------------------------------------------------------------------------------- /menubar/menubar.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 112488FA1E521A3400EE2AA9 /* InterfaceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112488F91E521A3400EE2AA9 /* InterfaceViewController.swift */; }; 11 | 112488FC1E523CC600EE2AA9 /* Socket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112488FB1E523CC600EE2AA9 /* Socket.swift */; }; 12 | 112488FE1E523D5000EE2AA9 /* SocketViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112488FD1E523D5000EE2AA9 /* SocketViewController.swift */; }; 13 | 112489011E52441800EE2AA9 /* IpFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112489001E52441800EE2AA9 /* IpFilter.swift */; }; 14 | 112489031E53609E00EE2AA9 /* IpViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112489021E53609E00EE2AA9 /* IpViewController.swift */; }; 15 | 1131BE931E42438200DCAD53 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1131BE921E42438200DCAD53 /* AppDelegate.swift */; }; 16 | 1131BE951E42438200DCAD53 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1131BE941E42438200DCAD53 /* Assets.xcassets */; }; 17 | 1131BE981E42438200DCAD53 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1131BE961E42438200DCAD53 /* MainMenu.xib */; }; 18 | 1131BEA31E42438300DCAD53 /* t2Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1131BEA21E42438300DCAD53 /* t2Tests.swift */; }; 19 | 1131BEAE1E42438300DCAD53 /* t2UITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1131BEAD1E42438300DCAD53 /* t2UITests.swift */; }; 20 | 1131BEBC1E4244AE00DCAD53 /* MyMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1131BEBB1E4244AE00DCAD53 /* MyMenu.swift */; }; 21 | 1131BEBE1E424A0300DCAD53 /* Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1131BEBD1E424A0300DCAD53 /* Interface.swift */; }; 22 | 114864021E43A185008CEE02 /* CHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 114864011E43A185008CEE02 /* CHelper.swift */; }; 23 | 1153F5CB1E49033500804F43 /* SettingsWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1153F5CA1E49033500804F43 /* SettingsWindow.swift */; }; 24 | 11BA22251E4D0AF100B284C0 /* TSTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11BA22241E4D0AF100B284C0 /* TSTextField.swift */; }; 25 | 11BA22271E4D0B1A00B284C0 /* TSClipView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11BA22261E4D0B1A00B284C0 /* TSClipView.swift */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXContainerItemProxy section */ 29 | 1131BE9F1E42438300DCAD53 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = 1131BE871E42438200DCAD53 /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = 1131BE8E1E42438200DCAD53; 34 | remoteInfo = t2; 35 | }; 36 | 1131BEAA1E42438300DCAD53 /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = 1131BE871E42438200DCAD53 /* Project object */; 39 | proxyType = 1; 40 | remoteGlobalIDString = 1131BE8E1E42438200DCAD53; 41 | remoteInfo = t2; 42 | }; 43 | /* End PBXContainerItemProxy section */ 44 | 45 | /* Begin PBXFileReference section */ 46 | 112488F91E521A3400EE2AA9 /* InterfaceViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InterfaceViewController.swift; sourceTree = ""; }; 47 | 112488FB1E523CC600EE2AA9 /* Socket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Socket.swift; sourceTree = ""; }; 48 | 112488FD1E523D5000EE2AA9 /* SocketViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketViewController.swift; sourceTree = ""; }; 49 | 112489001E52441800EE2AA9 /* IpFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IpFilter.swift; sourceTree = ""; }; 50 | 112489021E53609E00EE2AA9 /* IpViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IpViewController.swift; sourceTree = ""; }; 51 | 1131BE8F1E42438200DCAD53 /* netfil.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = netfil.app; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | 1131BE921E42438200DCAD53 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 53 | 1131BE941E42438200DCAD53 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 54 | 1131BE971E42438200DCAD53 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 55 | 1131BE991E42438200DCAD53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | 1131BE9E1E42438300DCAD53 /* netfilTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = netfilTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | 1131BEA21E42438300DCAD53 /* t2Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = t2Tests.swift; sourceTree = ""; }; 58 | 1131BEA41E42438300DCAD53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 59 | 1131BEA91E42438300DCAD53 /* netfilUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = netfilUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 60 | 1131BEAD1E42438300DCAD53 /* t2UITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = t2UITests.swift; sourceTree = ""; }; 61 | 1131BEAF1E42438300DCAD53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 62 | 1131BEBB1E4244AE00DCAD53 /* MyMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyMenu.swift; sourceTree = ""; }; 63 | 1131BEBD1E424A0300DCAD53 /* Interface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Interface.swift; sourceTree = ""; }; 64 | 1131BEBF1E424F3A00DCAD53 /* menubar-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "menubar-Bridging-Header.h"; sourceTree = ""; }; 65 | 1131BEC01E42508D00DCAD53 /* cstuff.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cstuff.h; sourceTree = ""; }; 66 | 114864011E43A185008CEE02 /* CHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CHelper.swift; sourceTree = ""; }; 67 | 1153F5CA1E49033500804F43 /* SettingsWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsWindow.swift; sourceTree = ""; }; 68 | 11BA22241E4D0AF100B284C0 /* TSTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TSTextField.swift; sourceTree = ""; }; 69 | 11BA22261E4D0B1A00B284C0 /* TSClipView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TSClipView.swift; sourceTree = ""; }; 70 | /* End PBXFileReference section */ 71 | 72 | /* Begin PBXFrameworksBuildPhase section */ 73 | 1131BE8C1E42438200DCAD53 /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | 1131BE9B1E42438300DCAD53 /* Frameworks */ = { 81 | isa = PBXFrameworksBuildPhase; 82 | buildActionMask = 2147483647; 83 | files = ( 84 | ); 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | 1131BEA61E42438300DCAD53 /* Frameworks */ = { 88 | isa = PBXFrameworksBuildPhase; 89 | buildActionMask = 2147483647; 90 | files = ( 91 | ); 92 | runOnlyForDeploymentPostprocessing = 0; 93 | }; 94 | /* End PBXFrameworksBuildPhase section */ 95 | 96 | /* Begin PBXGroup section */ 97 | 112488FF1E52437F00EE2AA9 /* C Assistance */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 114864011E43A185008CEE02 /* CHelper.swift */, 101 | 1131BEBF1E424F3A00DCAD53 /* menubar-Bridging-Header.h */, 102 | 1131BEC01E42508D00DCAD53 /* cstuff.h */, 103 | ); 104 | name = "C Assistance"; 105 | sourceTree = ""; 106 | }; 107 | 1131BE861E42438200DCAD53 = { 108 | isa = PBXGroup; 109 | children = ( 110 | 1131BE911E42438200DCAD53 /* netfil */, 111 | 1131BEA11E42438300DCAD53 /* netfilTests */, 112 | 1131BEAC1E42438300DCAD53 /* netfilUITests */, 113 | 1131BE901E42438200DCAD53 /* Products */, 114 | ); 115 | sourceTree = ""; 116 | }; 117 | 1131BE901E42438200DCAD53 /* Products */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | 1131BE8F1E42438200DCAD53 /* netfil.app */, 121 | 1131BE9E1E42438300DCAD53 /* netfilTests.xctest */, 122 | 1131BEA91E42438300DCAD53 /* netfilUITests.xctest */, 123 | ); 124 | name = Products; 125 | sourceTree = ""; 126 | }; 127 | 1131BE911E42438200DCAD53 /* netfil */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | 112488FF1E52437F00EE2AA9 /* C Assistance */, 131 | 1131BE941E42438200DCAD53 /* Assets.xcassets */, 132 | 1131BE961E42438200DCAD53 /* MainMenu.xib */, 133 | 1131BE921E42438200DCAD53 /* AppDelegate.swift */, 134 | 1131BEBB1E4244AE00DCAD53 /* MyMenu.swift */, 135 | 1153F5CA1E49033500804F43 /* SettingsWindow.swift */, 136 | 1131BEBD1E424A0300DCAD53 /* Interface.swift */, 137 | 112488F91E521A3400EE2AA9 /* InterfaceViewController.swift */, 138 | 112488FB1E523CC600EE2AA9 /* Socket.swift */, 139 | 112488FD1E523D5000EE2AA9 /* SocketViewController.swift */, 140 | 112489001E52441800EE2AA9 /* IpFilter.swift */, 141 | 112489021E53609E00EE2AA9 /* IpViewController.swift */, 142 | 11BA22241E4D0AF100B284C0 /* TSTextField.swift */, 143 | 11BA22261E4D0B1A00B284C0 /* TSClipView.swift */, 144 | 1131BE991E42438200DCAD53 /* Info.plist */, 145 | ); 146 | name = netfil; 147 | path = t2; 148 | sourceTree = ""; 149 | }; 150 | 1131BEA11E42438300DCAD53 /* netfilTests */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | 1131BEA21E42438300DCAD53 /* t2Tests.swift */, 154 | 1131BEA41E42438300DCAD53 /* Info.plist */, 155 | ); 156 | name = netfilTests; 157 | path = t2Tests; 158 | sourceTree = ""; 159 | }; 160 | 1131BEAC1E42438300DCAD53 /* netfilUITests */ = { 161 | isa = PBXGroup; 162 | children = ( 163 | 1131BEAD1E42438300DCAD53 /* t2UITests.swift */, 164 | 1131BEAF1E42438300DCAD53 /* Info.plist */, 165 | ); 166 | name = netfilUITests; 167 | path = t2UITests; 168 | sourceTree = ""; 169 | }; 170 | /* End PBXGroup section */ 171 | 172 | /* Begin PBXNativeTarget section */ 173 | 1131BE8E1E42438200DCAD53 /* netfil */ = { 174 | isa = PBXNativeTarget; 175 | buildConfigurationList = 1131BEB21E42438300DCAD53 /* Build configuration list for PBXNativeTarget "netfil" */; 176 | buildPhases = ( 177 | 1131BE8B1E42438200DCAD53 /* Sources */, 178 | 1131BE8C1E42438200DCAD53 /* Frameworks */, 179 | 1131BE8D1E42438200DCAD53 /* Resources */, 180 | ); 181 | buildRules = ( 182 | ); 183 | dependencies = ( 184 | ); 185 | name = netfil; 186 | productName = t2; 187 | productReference = 1131BE8F1E42438200DCAD53 /* netfil.app */; 188 | productType = "com.apple.product-type.application"; 189 | }; 190 | 1131BE9D1E42438300DCAD53 /* netfilTests */ = { 191 | isa = PBXNativeTarget; 192 | buildConfigurationList = 1131BEB51E42438300DCAD53 /* Build configuration list for PBXNativeTarget "netfilTests" */; 193 | buildPhases = ( 194 | 1131BE9A1E42438300DCAD53 /* Sources */, 195 | 1131BE9B1E42438300DCAD53 /* Frameworks */, 196 | 1131BE9C1E42438300DCAD53 /* Resources */, 197 | ); 198 | buildRules = ( 199 | ); 200 | dependencies = ( 201 | 1131BEA01E42438300DCAD53 /* PBXTargetDependency */, 202 | ); 203 | name = netfilTests; 204 | productName = t2Tests; 205 | productReference = 1131BE9E1E42438300DCAD53 /* netfilTests.xctest */; 206 | productType = "com.apple.product-type.bundle.unit-test"; 207 | }; 208 | 1131BEA81E42438300DCAD53 /* netfilUITests */ = { 209 | isa = PBXNativeTarget; 210 | buildConfigurationList = 1131BEB81E42438300DCAD53 /* Build configuration list for PBXNativeTarget "netfilUITests" */; 211 | buildPhases = ( 212 | 1131BEA51E42438300DCAD53 /* Sources */, 213 | 1131BEA61E42438300DCAD53 /* Frameworks */, 214 | 1131BEA71E42438300DCAD53 /* Resources */, 215 | ); 216 | buildRules = ( 217 | ); 218 | dependencies = ( 219 | 1131BEAB1E42438300DCAD53 /* PBXTargetDependency */, 220 | ); 221 | name = netfilUITests; 222 | productName = t2UITests; 223 | productReference = 1131BEA91E42438300DCAD53 /* netfilUITests.xctest */; 224 | productType = "com.apple.product-type.bundle.ui-testing"; 225 | }; 226 | /* End PBXNativeTarget section */ 227 | 228 | /* Begin PBXProject section */ 229 | 1131BE871E42438200DCAD53 /* Project object */ = { 230 | isa = PBXProject; 231 | attributes = { 232 | LastSwiftUpdateCheck = 0820; 233 | LastUpgradeCheck = 0820; 234 | ORGANIZATIONNAME = ""; 235 | TargetAttributes = { 236 | 1131BE8E1E42438200DCAD53 = { 237 | CreatedOnToolsVersion = 8.2; 238 | ProvisioningStyle = Automatic; 239 | }; 240 | 1131BE9D1E42438300DCAD53 = { 241 | CreatedOnToolsVersion = 8.2; 242 | ProvisioningStyle = Automatic; 243 | TestTargetID = 1131BE8E1E42438200DCAD53; 244 | }; 245 | 1131BEA81E42438300DCAD53 = { 246 | CreatedOnToolsVersion = 8.2; 247 | ProvisioningStyle = Automatic; 248 | TestTargetID = 1131BE8E1E42438200DCAD53; 249 | }; 250 | }; 251 | }; 252 | buildConfigurationList = 1131BE8A1E42438200DCAD53 /* Build configuration list for PBXProject "menubar" */; 253 | compatibilityVersion = "Xcode 3.2"; 254 | developmentRegion = English; 255 | hasScannedForEncodings = 0; 256 | knownRegions = ( 257 | en, 258 | Base, 259 | ); 260 | mainGroup = 1131BE861E42438200DCAD53; 261 | productRefGroup = 1131BE901E42438200DCAD53 /* Products */; 262 | projectDirPath = ""; 263 | projectRoot = ""; 264 | targets = ( 265 | 1131BE8E1E42438200DCAD53 /* netfil */, 266 | 1131BE9D1E42438300DCAD53 /* netfilTests */, 267 | 1131BEA81E42438300DCAD53 /* netfilUITests */, 268 | ); 269 | }; 270 | /* End PBXProject section */ 271 | 272 | /* Begin PBXResourcesBuildPhase section */ 273 | 1131BE8D1E42438200DCAD53 /* Resources */ = { 274 | isa = PBXResourcesBuildPhase; 275 | buildActionMask = 2147483647; 276 | files = ( 277 | 1131BE951E42438200DCAD53 /* Assets.xcassets in Resources */, 278 | 1131BE981E42438200DCAD53 /* MainMenu.xib in Resources */, 279 | ); 280 | runOnlyForDeploymentPostprocessing = 0; 281 | }; 282 | 1131BE9C1E42438300DCAD53 /* Resources */ = { 283 | isa = PBXResourcesBuildPhase; 284 | buildActionMask = 2147483647; 285 | files = ( 286 | ); 287 | runOnlyForDeploymentPostprocessing = 0; 288 | }; 289 | 1131BEA71E42438300DCAD53 /* Resources */ = { 290 | isa = PBXResourcesBuildPhase; 291 | buildActionMask = 2147483647; 292 | files = ( 293 | ); 294 | runOnlyForDeploymentPostprocessing = 0; 295 | }; 296 | /* End PBXResourcesBuildPhase section */ 297 | 298 | /* Begin PBXSourcesBuildPhase section */ 299 | 1131BE8B1E42438200DCAD53 /* Sources */ = { 300 | isa = PBXSourcesBuildPhase; 301 | buildActionMask = 2147483647; 302 | files = ( 303 | 112488FA1E521A3400EE2AA9 /* InterfaceViewController.swift in Sources */, 304 | 1131BEBC1E4244AE00DCAD53 /* MyMenu.swift in Sources */, 305 | 1131BE931E42438200DCAD53 /* AppDelegate.swift in Sources */, 306 | 112489011E52441800EE2AA9 /* IpFilter.swift in Sources */, 307 | 11BA22271E4D0B1A00B284C0 /* TSClipView.swift in Sources */, 308 | 112489031E53609E00EE2AA9 /* IpViewController.swift in Sources */, 309 | 11BA22251E4D0AF100B284C0 /* TSTextField.swift in Sources */, 310 | 112488FE1E523D5000EE2AA9 /* SocketViewController.swift in Sources */, 311 | 112488FC1E523CC600EE2AA9 /* Socket.swift in Sources */, 312 | 1131BEBE1E424A0300DCAD53 /* Interface.swift in Sources */, 313 | 114864021E43A185008CEE02 /* CHelper.swift in Sources */, 314 | 1153F5CB1E49033500804F43 /* SettingsWindow.swift in Sources */, 315 | ); 316 | runOnlyForDeploymentPostprocessing = 0; 317 | }; 318 | 1131BE9A1E42438300DCAD53 /* Sources */ = { 319 | isa = PBXSourcesBuildPhase; 320 | buildActionMask = 2147483647; 321 | files = ( 322 | 1131BEA31E42438300DCAD53 /* t2Tests.swift in Sources */, 323 | ); 324 | runOnlyForDeploymentPostprocessing = 0; 325 | }; 326 | 1131BEA51E42438300DCAD53 /* Sources */ = { 327 | isa = PBXSourcesBuildPhase; 328 | buildActionMask = 2147483647; 329 | files = ( 330 | 1131BEAE1E42438300DCAD53 /* t2UITests.swift in Sources */, 331 | ); 332 | runOnlyForDeploymentPostprocessing = 0; 333 | }; 334 | /* End PBXSourcesBuildPhase section */ 335 | 336 | /* Begin PBXTargetDependency section */ 337 | 1131BEA01E42438300DCAD53 /* PBXTargetDependency */ = { 338 | isa = PBXTargetDependency; 339 | target = 1131BE8E1E42438200DCAD53 /* netfil */; 340 | targetProxy = 1131BE9F1E42438300DCAD53 /* PBXContainerItemProxy */; 341 | }; 342 | 1131BEAB1E42438300DCAD53 /* PBXTargetDependency */ = { 343 | isa = PBXTargetDependency; 344 | target = 1131BE8E1E42438200DCAD53 /* netfil */; 345 | targetProxy = 1131BEAA1E42438300DCAD53 /* PBXContainerItemProxy */; 346 | }; 347 | /* End PBXTargetDependency section */ 348 | 349 | /* Begin PBXVariantGroup section */ 350 | 1131BE961E42438200DCAD53 /* MainMenu.xib */ = { 351 | isa = PBXVariantGroup; 352 | children = ( 353 | 1131BE971E42438200DCAD53 /* Base */, 354 | ); 355 | name = MainMenu.xib; 356 | sourceTree = ""; 357 | }; 358 | /* End PBXVariantGroup section */ 359 | 360 | /* Begin XCBuildConfiguration section */ 361 | 1131BEB01E42438300DCAD53 /* Debug */ = { 362 | isa = XCBuildConfiguration; 363 | buildSettings = { 364 | ALWAYS_SEARCH_USER_PATHS = NO; 365 | CLANG_ANALYZER_NONNULL = YES; 366 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 367 | CLANG_CXX_LIBRARY = "libc++"; 368 | CLANG_ENABLE_MODULES = YES; 369 | CLANG_ENABLE_OBJC_ARC = YES; 370 | CLANG_WARN_BOOL_CONVERSION = YES; 371 | CLANG_WARN_CONSTANT_CONVERSION = YES; 372 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 373 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 374 | CLANG_WARN_EMPTY_BODY = YES; 375 | CLANG_WARN_ENUM_CONVERSION = YES; 376 | CLANG_WARN_INFINITE_RECURSION = YES; 377 | CLANG_WARN_INT_CONVERSION = YES; 378 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 379 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 380 | CLANG_WARN_UNREACHABLE_CODE = YES; 381 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 382 | CODE_SIGN_IDENTITY = "-"; 383 | COPY_PHASE_STRIP = NO; 384 | DEBUG_INFORMATION_FORMAT = dwarf; 385 | ENABLE_STRICT_OBJC_MSGSEND = YES; 386 | ENABLE_TESTABILITY = YES; 387 | GCC_C_LANGUAGE_STANDARD = gnu99; 388 | GCC_DYNAMIC_NO_PIC = NO; 389 | GCC_NO_COMMON_BLOCKS = YES; 390 | GCC_OPTIMIZATION_LEVEL = 0; 391 | GCC_PREPROCESSOR_DEFINITIONS = ( 392 | "DEBUG=1", 393 | "$(inherited)", 394 | ); 395 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 396 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 397 | GCC_WARN_UNDECLARED_SELECTOR = YES; 398 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 399 | GCC_WARN_UNUSED_FUNCTION = YES; 400 | GCC_WARN_UNUSED_VARIABLE = YES; 401 | MACOSX_DEPLOYMENT_TARGET = 10.12; 402 | MTL_ENABLE_DEBUG_INFO = YES; 403 | ONLY_ACTIVE_ARCH = YES; 404 | SDKROOT = macosx; 405 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 406 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 407 | }; 408 | name = Debug; 409 | }; 410 | 1131BEB11E42438300DCAD53 /* Release */ = { 411 | isa = XCBuildConfiguration; 412 | buildSettings = { 413 | ALWAYS_SEARCH_USER_PATHS = NO; 414 | CLANG_ANALYZER_NONNULL = YES; 415 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 416 | CLANG_CXX_LIBRARY = "libc++"; 417 | CLANG_ENABLE_MODULES = YES; 418 | CLANG_ENABLE_OBJC_ARC = YES; 419 | CLANG_WARN_BOOL_CONVERSION = YES; 420 | CLANG_WARN_CONSTANT_CONVERSION = YES; 421 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 422 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 423 | CLANG_WARN_EMPTY_BODY = YES; 424 | CLANG_WARN_ENUM_CONVERSION = YES; 425 | CLANG_WARN_INFINITE_RECURSION = YES; 426 | CLANG_WARN_INT_CONVERSION = YES; 427 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 428 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 429 | CLANG_WARN_UNREACHABLE_CODE = YES; 430 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 431 | CODE_SIGN_IDENTITY = "-"; 432 | COPY_PHASE_STRIP = NO; 433 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 434 | ENABLE_NS_ASSERTIONS = NO; 435 | ENABLE_STRICT_OBJC_MSGSEND = YES; 436 | GCC_C_LANGUAGE_STANDARD = gnu99; 437 | GCC_NO_COMMON_BLOCKS = YES; 438 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 439 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 440 | GCC_WARN_UNDECLARED_SELECTOR = YES; 441 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 442 | GCC_WARN_UNUSED_FUNCTION = YES; 443 | GCC_WARN_UNUSED_VARIABLE = YES; 444 | MACOSX_DEPLOYMENT_TARGET = 10.12; 445 | MTL_ENABLE_DEBUG_INFO = NO; 446 | SDKROOT = macosx; 447 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 448 | }; 449 | name = Release; 450 | }; 451 | 1131BEB31E42438300DCAD53 /* Debug */ = { 452 | isa = XCBuildConfiguration; 453 | buildSettings = { 454 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 455 | COMBINE_HIDPI_IMAGES = YES; 456 | INFOPLIST_FILE = t2/Info.plist; 457 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 458 | PRODUCT_BUNDLE_IDENTIFIER = com.company.netfilmenu; 459 | PRODUCT_NAME = "$(TARGET_NAME)"; 460 | SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/t2/$(PROJECT_NAME)-Bridging-Header.h"; 461 | SWIFT_VERSION = 3.0; 462 | }; 463 | name = Debug; 464 | }; 465 | 1131BEB41E42438300DCAD53 /* Release */ = { 466 | isa = XCBuildConfiguration; 467 | buildSettings = { 468 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 469 | COMBINE_HIDPI_IMAGES = YES; 470 | INFOPLIST_FILE = t2/Info.plist; 471 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 472 | PRODUCT_BUNDLE_IDENTIFIER = com.company.netfilmenu; 473 | PRODUCT_NAME = "$(TARGET_NAME)"; 474 | SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/t2/$(PROJECT_NAME)-Bridging-Header.h"; 475 | SWIFT_VERSION = 3.0; 476 | }; 477 | name = Release; 478 | }; 479 | 1131BEB61E42438300DCAD53 /* Debug */ = { 480 | isa = XCBuildConfiguration; 481 | buildSettings = { 482 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 483 | BUNDLE_LOADER = "$(TEST_HOST)"; 484 | COMBINE_HIDPI_IMAGES = YES; 485 | INFOPLIST_FILE = t2Tests/Info.plist; 486 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 487 | PRODUCT_BUNDLE_IDENTIFIER = com.company.t2Tests; 488 | PRODUCT_NAME = "$(TARGET_NAME)"; 489 | SWIFT_VERSION = 3.0; 490 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/t2.app/Contents/MacOS/t2"; 491 | }; 492 | name = Debug; 493 | }; 494 | 1131BEB71E42438300DCAD53 /* Release */ = { 495 | isa = XCBuildConfiguration; 496 | buildSettings = { 497 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 498 | BUNDLE_LOADER = "$(TEST_HOST)"; 499 | COMBINE_HIDPI_IMAGES = YES; 500 | INFOPLIST_FILE = t2Tests/Info.plist; 501 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 502 | PRODUCT_BUNDLE_IDENTIFIER = com.company.t2Tests; 503 | PRODUCT_NAME = "$(TARGET_NAME)"; 504 | SWIFT_VERSION = 3.0; 505 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/t2.app/Contents/MacOS/t2"; 506 | }; 507 | name = Release; 508 | }; 509 | 1131BEB91E42438300DCAD53 /* Debug */ = { 510 | isa = XCBuildConfiguration; 511 | buildSettings = { 512 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 513 | COMBINE_HIDPI_IMAGES = YES; 514 | INFOPLIST_FILE = t2UITests/Info.plist; 515 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 516 | PRODUCT_BUNDLE_IDENTIFIER = com.company.t2UITests; 517 | PRODUCT_NAME = "$(TARGET_NAME)"; 518 | SWIFT_VERSION = 3.0; 519 | TEST_TARGET_NAME = t2; 520 | }; 521 | name = Debug; 522 | }; 523 | 1131BEBA1E42438300DCAD53 /* Release */ = { 524 | isa = XCBuildConfiguration; 525 | buildSettings = { 526 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 527 | COMBINE_HIDPI_IMAGES = YES; 528 | INFOPLIST_FILE = t2UITests/Info.plist; 529 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 530 | PRODUCT_BUNDLE_IDENTIFIER = com.company.t2UITests; 531 | PRODUCT_NAME = "$(TARGET_NAME)"; 532 | SWIFT_VERSION = 3.0; 533 | TEST_TARGET_NAME = t2; 534 | }; 535 | name = Release; 536 | }; 537 | /* End XCBuildConfiguration section */ 538 | 539 | /* Begin XCConfigurationList section */ 540 | 1131BE8A1E42438200DCAD53 /* Build configuration list for PBXProject "menubar" */ = { 541 | isa = XCConfigurationList; 542 | buildConfigurations = ( 543 | 1131BEB01E42438300DCAD53 /* Debug */, 544 | 1131BEB11E42438300DCAD53 /* Release */, 545 | ); 546 | defaultConfigurationIsVisible = 0; 547 | defaultConfigurationName = Release; 548 | }; 549 | 1131BEB21E42438300DCAD53 /* Build configuration list for PBXNativeTarget "netfil" */ = { 550 | isa = XCConfigurationList; 551 | buildConfigurations = ( 552 | 1131BEB31E42438300DCAD53 /* Debug */, 553 | 1131BEB41E42438300DCAD53 /* Release */, 554 | ); 555 | defaultConfigurationIsVisible = 0; 556 | defaultConfigurationName = Release; 557 | }; 558 | 1131BEB51E42438300DCAD53 /* Build configuration list for PBXNativeTarget "netfilTests" */ = { 559 | isa = XCConfigurationList; 560 | buildConfigurations = ( 561 | 1131BEB61E42438300DCAD53 /* Debug */, 562 | 1131BEB71E42438300DCAD53 /* Release */, 563 | ); 564 | defaultConfigurationIsVisible = 0; 565 | defaultConfigurationName = Release; 566 | }; 567 | 1131BEB81E42438300DCAD53 /* Build configuration list for PBXNativeTarget "netfilUITests" */ = { 568 | isa = XCConfigurationList; 569 | buildConfigurations = ( 570 | 1131BEB91E42438300DCAD53 /* Debug */, 571 | 1131BEBA1E42438300DCAD53 /* Release */, 572 | ); 573 | defaultConfigurationIsVisible = 0; 574 | defaultConfigurationName = Release; 575 | }; 576 | /* End XCConfigurationList section */ 577 | }; 578 | rootObject = 1131BE871E42438200DCAD53 /* Project object */; 579 | } 580 | --------------------------------------------------------------------------------