netplaySniff – Diff between revs 9 and 10

Subversion Repositories:
Rev:
Show entire fileIgnore whitespace
Rev 9 Rev 10
Line 15... Line 15...
15 const { exec } = require("child_process") 15 const { exec } = require("child_process")
16 const Inotify = require('inotify-remastered').Inotify 16 const Inotify = require('inotify-remastered').Inotify
17 const inotify = new Inotify() 17 const inotify = new Inotify()
18 const sqlite = require('sqlite3') 18 const sqlite = require('sqlite3')
19 const { Command } = require('commander') 19 const { Command } = require('commander')
-   20 const net = require('net')
Line 20... Line 21...
20   21  
21 // set up logger 22 // set up logger
22 const logger = createLogger({ 23 const logger = createLogger({
23 format: format.combine( 24 format: format.combine(
Line 33... Line 34...
33 timestamp: true 34 timestamp: true
34 }), 35 }),
35 new transports.File( 36 new transports.File(
36 { 37 {
37 timestamp: true, 38 timestamp: true,
38 filename: path.join(path.dirname(fs.realpathSync(__filename)), "log/netplaySniff.log") 39 filename: path.join(path.dirname(fs.realpathSync(__filename)), 'log/netplaySniff.log')
39 } 40 }
40 ) 41 )
41 ] 42 ]
42 }) 43 })
Line 56... Line 57...
56 .command('run') 57 .command('run')
57 .option('-c, --config <path>', 'path to the configuration file', 'config.yml') 58 .option('-c, --config <path>', 'path to the configuration file', 'config.yml')
58 .option('-d, --database <path>', 'the path where to store a database', 'db/players.db') 59 .option('-d, --database <path>', 'the path where to store a database', 'db/players.db')
59 .description('run the program as a daemon') 60 .description('run the program as a daemon')
60 .action((options) => { 61 .action((options) => {
61 logger.info(`running as a daemon with configuraton options from ${options.config} and database at ${options.database}`) 62 logger.info(`running as a daemon with configuration from ${options.config} and database at ${options.database}`)
Line -... Line 63...
-   63  
-   64 // load configuration file.
Line 62... Line 65...
62   65 var config = YAML.load(options.config)
63   66  
64 // Watch the configuration file for changes. 67 // Watch the configuration file for changes.
65 const configWatch = inotify.addWatch({ 68 inotify.addWatch({
66 path: options.config, 69 path: options.config,
67 watch_for: Inotify.IN_MODIFY, 70 watch_for: Inotify.IN_MODIFY,
68 callback: function (event) { 71 callback: function (event) {
69 logger.info(`Reloading configuration file config.yml`) -  
70 config = YAML.load(options.config) 72 logger.info(`Reloading configuration file config.yml`)
71 config.db.file = options.database 73 config = YAML.load(options.config)
Line 72... Line -...
72 } -  
73 }) -  
74   -  
75 // load configuration file. -  
76 var config = YAML.load(options.config) -  
77 // override configuration options with command-line options 74 }
Line 78... Line 75...
78 config.db.file = options.database 75 })
79   76  
80 const mqttClient = mqtt.connect(config.mqtt.connect) 77 const mqttClient = mqtt.connect(config.mqtt.connect)
Line 104... Line 101...
104 logger.error(`MQTT ${error}`) 101 logger.error(`MQTT ${error}`)
105 console.log(error) 102 console.log(error)
106 }) 103 })
Line 107... Line 104...
107   104  
-   105 // set up packet capture
-   106 logger.info(`setting up packet capture`)
108 // set up packet capture 107  
109 const cap = new Cap() -  
110 let device = {} -  
111 switch (config.router) { -  
112 case 'any': -  
113 device = config.router -  
114 break; -  
115 default: -  
116 device = Cap.findDevice(`${config.router}`) -  
117 break; -  
118 } 108 const cap = new Cap()
119 const filter = `tcp and dst port ${config.netplay.port} and dst host ${config.netplay.host}` 109 const filter = `tcp and dst port ${config.netplay.port}`
120 const bufSize = 10 * 1024 * 1024 110 const bufSize = 10 * 1024 * 1024
121 const buffer = Buffer.alloc(65535) 111 const buffer = Buffer.alloc(65535)
122 const linkType = cap.open(device, filter, bufSize, buffer) 112 const linkType = cap.open('any', filter, bufSize, buffer)
123 cap.setMinBytes && cap.setMinBytes(0) 113 cap.setMinBytes && cap.setMinBytes(0)
124 cap.on('packet', (bytes, truncated) => processPacket(bytes, truncated, config, mqttClient)) -  
125   114 cap.on('packet', () => {
126 let netplay = {} 115 let netplay = {}
127 if (linkType !== 'ETHERNET') { -  
128 return -  
129 } -  
130   -  
131 var ret = decoders.Ethernet(buffer) -  
132   -  
133 if (ret.info.type !== PROTOCOL.ETHERNET.IPV4) { -  
134 return -  
135 } -  
136   -  
137 ret = decoders.IPV4(buffer, ret.offset) -  
138 netplay.ip = ret.info.srcaddr -  
139   -  
140 if (ret.info.protocol !== PROTOCOL.IP.TCP) { 116 if (linkType !== 'ETHERNET') {
141 return 117 return
142 } -  
143   -  
144 var dataLength = ret.info.totallen - ret.hdrlen -  
145   -  
146 ret = decoders.TCP(buffer, ret.offset) -  
Line 147... Line 118...
147 dataLength -= ret.hdrlen 118 }
-   119  
-   120 var ret = decoders.Ethernet(buffer)
-   121 if (ret.info.type !== PROTOCOL.ETHERNET.IPV4) {
Line 148... Line 122...
148   122 return
-   123 }
-   124  
149 var payload = buffer.subarray(ret.offset, ret.offset + dataLength) 125 ret = decoders.IPV4(buffer, ret.offset)
-   126 netplay.ip = ret.info.srcaddr
150   127 netplay.to = ret.info.dstaddr
151 // look for the NETPLAY_CMD_NICK in "netplay_private.h" data marker. 128 if (ret.info.protocol !== PROTOCOL.IP.TCP) {
Line 152... Line -...
152 if (payload.indexOf('0020', 0, "hex") !== 2) { -  
153 return -  
154 } -  
155   129 logger.info(`not a tcp protocol`)
Line 156... Line 130...
156 // remove NULL and NETPLAY_CMD_NICK 130 return
-   131 }
Line 157... Line 132...
157 netplay.nick = payload.toString().replace(/[\u0000\u0020]+/gi, '') 132  
158 netplay.hash = shortHash(`${netplay.nick}${netplay.ip}`) 133 var dataLength = ret.info.totallen - ret.hdrlen
159 netplay.time = new Date().toISOString() 134  
160   135 ret = decoders.TCP(buffer, ret.offset)
161 logger.info(`Player ${netplay.nick} joined via IP ${netplay.ip}`); 136 dataLength -= ret.hdrlen
Line -... Line 137...
-   137  
-   138 var payload = buffer.subarray(ret.offset, ret.offset + dataLength)
-   139 // look for the NETPLAY_CMD_NICK in "netplay_private.h" data marker.
-   140 if (payload.indexOf('0020', 0, "hex") !== 2) {
-   141 return
-   142 }
-   143  
162   144 // remove NULL and NETPLAY_CMD_NICK
163 const db = new sqlite.Database(config.db.file, sqlite.OPEN_CREATE | sqlite.OPEN_READWRITE | sqlite.OPEN_FULLMUTEX, (error) => { 145 netplay.nick = payload.toString().replace(/[\u0000\u0020]+/gi, '')
164 if (error) { 146 netplay.hash = shortHash(`${netplay.nick}${netplay.ip}`)
165 logger.error(`failed to open database: ${error}`) 147 netplay.time = new Date().toISOString()
166 return 148  
-   149 logger.info(`Player ${netplay.nick} joined via IP ${netplay.ip}`);
167 } 150  
168   151 const db = new sqlite.Database(config.db.file, sqlite.OPEN_CREATE | sqlite.OPEN_READWRITE | sqlite.OPEN_FULLMUTEX, (error) => {
169 db.run(`CREATE TABLE IF NOT EXISTS "players" ("nick" TEXT(15) NOT NULL, "ip" TEXT NOT NULL)`, (error, result) => { 152 if (error) {
170 if (error) { 153 logger.error(`failed to open database: ${config.db.file}`)
171 logger.error(`could not create database table: ${error}`); 154 return
-   155 }
-   156  
-   157 db.run(`CREATE TABLE IF NOT EXISTS "players" ("nick" TEXT(15) NOT NULL, "ip" TEXT NOT NULL)`, (error, result) => {
-   158 if (error) {
-   159 logger.error(`could not create database table: ${error}`);
Line 172... Line 160...
172 return 160 return
-   161 }
173 } 162 db.run(`INSERT INTO "players" ("nick", "ip") VALUES ($nick, $ip)`, { $nick: netplay.nick, $ip: netplay.ip }, (error) => {
174 db.run(`INSERT INTO "players" ("nick", "ip") VALUES ($nick, $ip)`, { $nick: netplay.nick, $ip: netplay.ip }, (error) => { 163 if (error) {
175 if (error) { -  
176 logger.error(`could not insert player and IP into database: ${error}`) -  
177 return -  
178 } -  
179   -  
180 logger.info(`player added to database`) -  
181 }) -  
Line 182... Line 164...
182 }) 164 logger.error(`could not insert player and IP into database: ${error}`)
183 }) -  
184   165 return
185 // send data to MQTT server 166 }
186 const data = JSON.stringify(netplay, null, 4) -  
187 mqttClient.publish(`${config.mqtt.topic}`, data, (error, packet) => { -  
188 logger.info(`player data sent to MQTT broker`) -  
189 }) -  
190   -  
191 // ban by nick. -  
192 let nickBanSet = new Set(config.bans.nicknames) 167  
193 if (nickBanSet.has(netplay.nick)) { -  
194 logger.info(`nick found to be banned: ${netplay.nick}`) -  
195 exec(`iptables -t mangle -A PREROUTING -p tcp --src ${netplay.ip} --dport ${config.netplay.port} -j DROP`, (error, stdout, stderr) => { -  
196 if (error) { -  
197 logger.error(`Error returned while banning connecting client ${error.message}`) -  
198 return -  
199 } 168 logger.info(`player added to database`)
-   169 })
-   170 })
-   171 })
-   172  
-   173 // send data to MQTT server
-   174 const data = JSON.stringify(netplay, null, 4)
-   175 mqttClient.publish(`${config.mqtt.topic}`, data, (error, packet) => {
-   176 logger.info(`player data sent to MQTT broker`)
-   177 })
-   178  
-   179 // ban by nick.
-   180 let nickBanSet = new Set(config.bans.nicknames)
-   181 if (nickBanSet.has(netplay.nick)) {
-   182 logger.info(`nick found to be banned: ${netplay.nick}`)
-   183 exec(`iptables -t mangle -A PREROUTING -p tcp --src ${netplay.ip} --dport ${config.netplay.port} -j DROP`, (error, stdout, stderr) => {
-   184 if (error) {
-   185 logger.error(`Error returned while banning connecting client ${error.message}`)
-   186 return
-   187 }
-   188 if (stderr) {
200 if (stderr) { 189 logger.error(`Standard error returned ${stderr}`)
201 logger.error(`Standard error returned ${stderr}`) 190 return
Line 202... Line 191...
202 return 191 }