Skip to content

Commit b09a8d3

Browse files
authored
Validate ip addresses (#176)
* validate ip addresses * fmt * cleaning unused var
1 parent 82969c7 commit b09a8d3

File tree

6 files changed

+7070
-200
lines changed

6 files changed

+7070
-200
lines changed

package-lock.json

Lines changed: 23 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"@subsquid/typeorm-store": "0.2.2",
3232
"axios": "^0.28.1",
3333
"dotenv": "^16.0.0",
34+
"ipaddr.js": "^2.2.0",
3435
"lodash": "^4.17.21",
3536
"pg": "^8.7.3",
3637
"pg-format": "^1.0.4",

src/mappings/contracts.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,8 @@ export async function contractCreated(
119119
})
120120

121121
if (contract.publicIps > 0 && touchedIps.length == 0) {
122-
console.log(`something went wrong with contract ${contractEvent.contractId}`)
123-
console.log(`ips: ${contract.publicIpsList}`)
124-
}
125-
126-
if (newNodeContract.contractID === BigInt(17661)) {
127-
console.log('contract found')
128-
console.log(touchedIps)
122+
ctx.log.warn(`Can't update IPs for contract ${contractEvent.contractId}`)
123+
ctx.log.warn(`ips: ${JSON.stringify(contract.publicIpsList.map(ip => { return { ip: ip.ip.toString(), gateway: ip.gateway.toString() } }))}`)
129124
}
130125

131126
await ctx.store.save(touchedIps)

src/mappings/farms.ts

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { Ctx } from '../processor'
66
import * as v63 from '../types/v63'
77
import { validateString } from "./nodes"
88

9+
import * as ipaddr from 'ipaddr.js';
10+
911
export class FarmWithIPs {
1012
constructor(farmID: number, ips: PublicIp[]) {
1113
this.farmID = farmID
@@ -56,6 +58,10 @@ export async function farmStored(
5658
await ctx.store.save<Farm>(newFarm)
5759

5860
const ipPromises = farmStoredEventParsed.publicIps.map(ip => {
61+
if (!checkIPs(ctx, ip.ip.toString(), ip.gateway.toString())) {
62+
return Promise.resolve()
63+
}
64+
5965
const newIP = new PublicIp()
6066

6167
newIP.id = item.event.id
@@ -67,13 +73,56 @@ export async function farmStored(
6773
newIP.farm = newFarm
6874

6975
newFarm.publicIPs?.push(newIP)
70-
76+
ctx.log.debug({ eventName: item.name, ip: newIP.ip }, `Public IP: ${newIP.ip} added with farm id: ${newFarm.farmID}`);
7177
return ctx.store.save<PublicIp>(newIP)
7278
})
7379
await Promise.all(ipPromises)
7480
await ctx.store.save<Farm>(newFarm)
7581
}
7682

83+
function checkIPs(ctx: Ctx, ipv4_a: string, ipv4_b: string): boolean {
84+
try {
85+
// Check if both IP addresses are valid
86+
if (!ipaddr.isValidCIDR(ipv4_a) || !ipaddr.isValid(ipv4_b)) {
87+
ctx.log.warn(`One or both IP addresses are invalid. Public IP: ${ipv4_a}, Gateway: ${ipv4_b}`);
88+
return false;
89+
}
90+
// Parse the IP addresses
91+
const ip_a = ipaddr.parseCIDR(ipv4_a);
92+
const ip_b = ipaddr.parse(ipv4_b);
93+
94+
// check if both IP addresses are the same
95+
if (ip_a[0] == ip_b) {
96+
ctx.log.warn(`The IP addresses are the same. Public IP: ${ipv4_a}, Gateway: ${ipv4_b}`);
97+
return false;
98+
}
99+
100+
// Check if both IP addresses are public
101+
if (ip_a[0].range() == 'private' || ip_b.range() == 'private') {
102+
ctx.log.warn(`One or both IP addresses are not public. Public IP: ${ipv4_a}, Gateway: ${ipv4_b}`);
103+
return false;
104+
}
105+
106+
// Check if both IP addresses are unicast addresses
107+
if (ip_a[0].range() !== 'unicast' || ip_b.range() !== 'unicast') {
108+
ctx.log.warn(`One or both IP addresses are not unicast addresses. Public IP: ${ipv4_a}, Gateway: ${ipv4_b}`);
109+
return false;
110+
}
111+
112+
113+
// Check if the gateway is in the same subnet as the host
114+
if (!ip_b.match(ip_a)) {
115+
ctx.log.warn(`The gateway is not in the same subnet as the host. Public IP: ${ipv4_a}, Gateway: ${ipv4_b}`);
116+
return false;
117+
}
118+
119+
return true;
120+
} catch (error: any) {
121+
ctx.log.error(`An error occurred: ${error.message}. Public IP: ${ipv4_a}, Gateway: ${ipv4_b}`);
122+
return false;
123+
}
124+
}
125+
77126
export async function farmUpdated(
78127
ctx: Ctx,
79128
item: EventItem<'TfgridModule.FarmUpdated', { event: { args: true } }>
@@ -122,8 +171,10 @@ export async function farmUpdated(
122171
savedFarm.certification = certification
123172

124173
let eventPublicIPs = farmUpdatedEventParsed.publicIps
125-
126-
await farmUpdatedEventParsed.publicIps.forEach(async ip => {
174+
farmUpdatedEventParsed.publicIps.forEach(async ip => {
175+
if (!checkIPs(ctx, ip.ip.toString(), ip.gateway.toString())) {
176+
return
177+
}
127178
if (ip.ip.toString().indexOf('\x00') >= 0) {
128179
return
129180
}
@@ -132,20 +183,24 @@ export async function farmUpdated(
132183
if (savedIP) {
133184
savedIP.ip = validateString(ctx, ip.ip.toString()) // not effective, but for since we already check for \x00
134185
savedIP.gateway = validateString(ctx, ip.gateway.toString())
186+
if (savedIP.farm.id !== savedFarm.id) {
187+
ctx.log.error({ eventName: item.name, ip: ip.ip.toString() }, `PublicIP: ${ip.ip.toString()} already exists on farm: ${savedIP.farm.farmID}, skiped adding it to farm with ID: ${savedFarm.farmID}`);
188+
}
135189
await ctx.store.save<PublicIp>(savedIP)
136190
} else {
191+
137192
const newIP = new PublicIp()
138193
newIP.id = item.event.id
139194
newIP.ip = validateString(ctx, ip.ip.toString())
140195
newIP.gateway = validateString(ctx, ip.gateway.toString())
141196
newIP.contractId = ip.contractId
142197
newIP.farm = savedFarm
143-
144198
await ctx.store.save<PublicIp>(newIP)
145199
if (!savedFarm.publicIPs) {
146200
savedFarm.publicIPs = []
147201
}
148202
savedFarm.publicIPs.push(newIP)
203+
ctx.log.debug({ eventName: item.name, ip: ip.ip.toString() }, `PublicIP: ${ip.ip.toString()} added with farm id: ${savedFarm.farmID}`);
149204
}
150205
})
151206

@@ -156,14 +211,19 @@ export async function farmUpdated(
156211
if (eventPublicIPs.filter(eventIp => validateString(ctx, eventIp.ip.toString()) === ip.ip).length === 0) {
157212
// IP got removed from farm
158213
await ctx.store.remove<PublicIp>(ip)
214+
// remove ip from savedFarm.publicIPs
215+
// savedFarm.publicIPs = savedFarm.publicIPs.filter(savedIP => savedIP.id !== ip.id)
216+
// TODO: check if we need this code above? or Cascade delete involving here?
217+
ctx.log.debug({ eventName: item.name, ip: ip.ip.toString() }, `PublicIP: ${ip.ip.toString()} in farm: ${savedFarm.farmID} removed from publicIPs`);
159218
}
160219
})
161220

162221
let farm = item.event.args as Farm
163222
if (farm.dedicatedFarm) {
164223
savedFarm.dedicatedFarm = farm.dedicatedFarm
165-
await ctx.store.save<Farm>(savedFarm)
166224
}
225+
await ctx.store.save<Farm>(savedFarm)
226+
167227
}
168228

169229
export async function farmDeleted(
@@ -176,6 +236,7 @@ export async function farmDeleted(
176236

177237
if (savedFarm) {
178238
await ctx.store.remove(savedFarm)
239+
ctx.log.debug({ eventName: item.name, farmID: savedFarm.farmID }, `Farm: ${savedFarm.farmID} removed from storage`);
179240
}
180241
}
181242

src/mappings/tftPrice.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,15 @@ export async function priceStored(
2020
let priceEvent
2121
if (priceStoredEvent.isV9) {
2222
priceEvent = BigDecimal(parseI16F16(new BN(priceStoredEvent.asV9[0], 'le'))) // [Uint8Array, Uint8Array] <- U16F16, AccountId
23-
ctx.log.debug("V9: block number: " + block.height.toString() + ", timestamp: " + timestamp.toString() + ", Price: " + priceEvent.toString() + ", Raw: " + priceStoredEvent.asV9[0])
23+
ctx.log.trace(`V9: block number: ${block.height}, timestamp: ${timestamp}, Price: ${priceEvent}, Raw: ${priceStoredEvent.asV9[0]}`)
2424

2525
} else if (priceStoredEvent.isV49) {
26-
// TODO: fix me U16F16 -> number
2726
priceEvent = BigDecimal(parseI16F16(new BN(priceStoredEvent.asV49, 'le'))) // Uint8Array <-U16F16
28-
ctx.log.debug("V49: block number: " + block.height.toString() + ", timestamp: " + timestamp.toString() + ", Price: " + priceEvent.toString() + ", Raw: " + priceStoredEvent.asV49[0])
27+
ctx.log.trace(`V49: block number: ${block.height}, timestamp: ${timestamp}, Price: ${priceEvent}, Raw: ${priceStoredEvent.asV49}`)
2928

3029
} else if (priceStoredEvent.isV101) {
31-
priceEvent = BigDecimal(priceStoredEvent.asV101/1000) // number <- u32 (milli USD)
32-
ctx.log.debug("V101: block number: " + block.height.toString() + ", timestamp: " + timestamp.toString() + ", Price: " + priceEvent.toString() + ", Raw: " + priceStoredEvent.asV101)
33-
30+
priceEvent = BigDecimal(priceStoredEvent.asV101 / 1000) // number <- u32 (milli USD)
31+
ctx.log.trace(`V101: block number: ${block.height}, timestamp: ${timestamp}, Price: ${priceEvent}, Raw: ${priceStoredEvent.asV101}`)
3432
}
3533

3634
if (!priceEvent) {
@@ -43,7 +41,7 @@ export async function priceStored(
4341
newPrice.block = block.height
4442
newPrice.timestamp = timestamp
4543
newPrice.newPrice = priceEvent
46-
44+
4745
await ctx.store.save<PriceStored>(newPrice)
4846
}
4947

@@ -57,7 +55,7 @@ export async function averagePriceStored(
5755

5856
let priceEvent
5957
if (averagePriceStoredEvent.isV105) {
60-
priceEvent = BigDecimal(averagePriceStoredEvent.asV105/1000) // number <- u32 (milli USD)
58+
priceEvent = BigDecimal(averagePriceStoredEvent.asV105 / 1000) // number <- u32 (milli USD)
6159
}
6260

6361
if (!priceEvent) {
@@ -70,7 +68,7 @@ export async function averagePriceStored(
7068
newPrice.block = block.height
7169
newPrice.timestamp = timestamp
7270
newPrice.newAveragePrice = priceEvent
73-
ctx.log.debug("V49: block number: " + block.height.toString() + ", timestamp: " + timestamp.toString() + ", Average Price: " + priceEvent.toString() + ", Raw: " + averagePriceStoredEvent.asV105)
71+
ctx.log.trace(`V105: block number: ${block.height}, timestamp: ${timestamp}, Average Price: ${priceEvent}, Raw: ${averagePriceStoredEvent.asV105}`);
7472

7573
await ctx.store.save<AveragePriceStored>(newPrice)
7674
}

0 commit comments

Comments
 (0)