Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate ip addresses #176

Merged
merged 3 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@subsquid/typeorm-store": "0.2.2",
"axios": "^0.28.1",
"dotenv": "^16.0.0",
"ipaddr.js": "^2.2.0",
"lodash": "^4.17.21",
"pg": "^8.7.3",
"pg-format": "^1.0.4",
Expand Down
9 changes: 2 additions & 7 deletions src/mappings/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,8 @@ export async function contractCreated(
})

if (contract.publicIps > 0 && touchedIps.length == 0) {
console.log(`something went wrong with contract ${contractEvent.contractId}`)
console.log(`ips: ${contract.publicIpsList}`)
}

if (newNodeContract.contractID === BigInt(17661)) {
console.log('contract found')
console.log(touchedIps)
ctx.log.warn(`Can't update IPs for contract ${contractEvent.contractId}`)
ctx.log.warn(`ips: ${JSON.stringify(contract.publicIpsList.map(ip => { return { ip: ip.ip.toString(), gateway: ip.gateway.toString() } }))}`)
}

await ctx.store.save(touchedIps)
Expand Down
71 changes: 66 additions & 5 deletions src/mappings/farms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { Ctx } from '../processor'
import * as v63 from '../types/v63'
import { validateString } from "./nodes"

import * as ipaddr from 'ipaddr.js';

export class FarmWithIPs {
constructor(farmID: number, ips: PublicIp[]) {
this.farmID = farmID
Expand Down Expand Up @@ -56,6 +58,10 @@ export async function farmStored(
await ctx.store.save<Farm>(newFarm)

const ipPromises = farmStoredEventParsed.publicIps.map(ip => {
if (!checkIPs(ctx, ip.ip.toString(), ip.gateway.toString())) {
return Promise.resolve()
}

const newIP = new PublicIp()

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

newFarm.publicIPs?.push(newIP)

ctx.log.debug({ eventName: item.name, ip: newIP.ip }, `Public IP: ${newIP.ip} added with farm id: ${newFarm.farmID}`);
return ctx.store.save<PublicIp>(newIP)
})
await Promise.all(ipPromises)
await ctx.store.save<Farm>(newFarm)
}

function checkIPs(ctx: Ctx, ipv4_a: string, ipv4_b: string): boolean {
try {
// Check if both IP addresses are valid
if (!ipaddr.isValidCIDR(ipv4_a) || !ipaddr.isValid(ipv4_b)) {
ctx.log.warn(`One or both IP addresses are invalid. Public IP: ${ipv4_a}, Gateway: ${ipv4_b}`);
return false;
}
// Parse the IP addresses
const ip_a = ipaddr.parseCIDR(ipv4_a);
const ip_b = ipaddr.parse(ipv4_b);

// check if both IP addresses are the same
if (ip_a[0] == ip_b) {
ctx.log.warn(`The IP addresses are the same. Public IP: ${ipv4_a}, Gateway: ${ipv4_b}`);
return false;
}

// Check if both IP addresses are public
if (ip_a[0].range() == 'private' || ip_b.range() == 'private') {
ctx.log.warn(`One or both IP addresses are not public. Public IP: ${ipv4_a}, Gateway: ${ipv4_b}`);
return false;
}

// Check if both IP addresses are unicast addresses
if (ip_a[0].range() !== 'unicast' || ip_b.range() !== 'unicast') {
ctx.log.warn(`One or both IP addresses are not unicast addresses. Public IP: ${ipv4_a}, Gateway: ${ipv4_b}`);
return false;
}


// Check if the gateway is in the same subnet as the host
if (!ip_b.match(ip_a)) {
ctx.log.warn(`The gateway is not in the same subnet as the host. Public IP: ${ipv4_a}, Gateway: ${ipv4_b}`);
return false;
}

return true;
} catch (error: any) {
ctx.log.error(`An error occurred: ${error.message}. Public IP: ${ipv4_a}, Gateway: ${ipv4_b}`);
return false;
}
}

export async function farmUpdated(
ctx: Ctx,
item: EventItem<'TfgridModule.FarmUpdated', { event: { args: true } }>
Expand Down Expand Up @@ -122,8 +171,10 @@ export async function farmUpdated(
savedFarm.certification = certification

let eventPublicIPs = farmUpdatedEventParsed.publicIps

await farmUpdatedEventParsed.publicIps.forEach(async ip => {
farmUpdatedEventParsed.publicIps.forEach(async ip => {
if (!checkIPs(ctx, ip.ip.toString(), ip.gateway.toString())) {
return
}
if (ip.ip.toString().indexOf('\x00') >= 0) {
return
}
Expand All @@ -132,20 +183,24 @@ export async function farmUpdated(
if (savedIP) {
savedIP.ip = validateString(ctx, ip.ip.toString()) // not effective, but for since we already check for \x00
savedIP.gateway = validateString(ctx, ip.gateway.toString())
if (savedIP.farm.id !== savedFarm.id) {
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}`);
}
await ctx.store.save<PublicIp>(savedIP)
} else {

const newIP = new PublicIp()
newIP.id = item.event.id
newIP.ip = validateString(ctx, ip.ip.toString())
newIP.gateway = validateString(ctx, ip.gateway.toString())
newIP.contractId = ip.contractId
newIP.farm = savedFarm

await ctx.store.save<PublicIp>(newIP)
if (!savedFarm.publicIPs) {
savedFarm.publicIPs = []
}
savedFarm.publicIPs.push(newIP)
ctx.log.debug({ eventName: item.name, ip: ip.ip.toString() }, `PublicIP: ${ip.ip.toString()} added with farm id: ${savedFarm.farmID}`);
}
})

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

let farm = item.event.args as Farm
if (farm.dedicatedFarm) {
savedFarm.dedicatedFarm = farm.dedicatedFarm
await ctx.store.save<Farm>(savedFarm)
}
await ctx.store.save<Farm>(savedFarm)

}

export async function farmDeleted(
Expand All @@ -176,6 +236,7 @@ export async function farmDeleted(

if (savedFarm) {
await ctx.store.remove(savedFarm)
ctx.log.debug({ eventName: item.name, farmID: savedFarm.farmID }, `Farm: ${savedFarm.farmID} removed from storage`);
}
}

Expand Down
16 changes: 7 additions & 9 deletions src/mappings/tftPrice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,15 @@ export async function priceStored(
let priceEvent
if (priceStoredEvent.isV9) {
priceEvent = BigDecimal(parseI16F16(new BN(priceStoredEvent.asV9[0], 'le'))) // [Uint8Array, Uint8Array] <- U16F16, AccountId
ctx.log.debug("V9: block number: " + block.height.toString() + ", timestamp: " + timestamp.toString() + ", Price: " + priceEvent.toString() + ", Raw: " + priceStoredEvent.asV9[0])
ctx.log.trace(`V9: block number: ${block.height}, timestamp: ${timestamp}, Price: ${priceEvent}, Raw: ${priceStoredEvent.asV9[0]}`)

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

} else if (priceStoredEvent.isV101) {
priceEvent = BigDecimal(priceStoredEvent.asV101/1000) // number <- u32 (milli USD)
ctx.log.debug("V101: block number: " + block.height.toString() + ", timestamp: " + timestamp.toString() + ", Price: " + priceEvent.toString() + ", Raw: " + priceStoredEvent.asV101)

priceEvent = BigDecimal(priceStoredEvent.asV101 / 1000) // number <- u32 (milli USD)
ctx.log.trace(`V101: block number: ${block.height}, timestamp: ${timestamp}, Price: ${priceEvent}, Raw: ${priceStoredEvent.asV101}`)
}

if (!priceEvent) {
Expand All @@ -43,7 +41,7 @@ export async function priceStored(
newPrice.block = block.height
newPrice.timestamp = timestamp
newPrice.newPrice = priceEvent

await ctx.store.save<PriceStored>(newPrice)
}

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

let priceEvent
if (averagePriceStoredEvent.isV105) {
priceEvent = BigDecimal(averagePriceStoredEvent.asV105/1000) // number <- u32 (milli USD)
priceEvent = BigDecimal(averagePriceStoredEvent.asV105 / 1000) // number <- u32 (milli USD)
}

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

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