Skip to content

Commit

Permalink
Add network details query. Use netip.Addr more
Browse files Browse the repository at this point in the history
  • Loading branch information
leighmacdonald committed Apr 1, 2024
1 parent 1c27667 commit 21742c8
Show file tree
Hide file tree
Showing 24 changed files with 467 additions and 236 deletions.
57 changes: 57 additions & 0 deletions frontend/src/api/profile.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { LatLng, LatLngLiteral } from 'leaflet';
import { LazyResult } from '../util/table.ts';
import { parseDateTime } from '../util/text.tsx';
import {
Expand Down Expand Up @@ -253,6 +254,62 @@ export const apiGetConnections = async (
return resp;
};

export type IPQuery = {
ip: string;
};

export type NetworkLocation = {
cidr: string;
country_code: string;
country_name: string;
region_name: string;
city_name: string;
lat_long: {
latitude: number;
longitude: number;
};
};

export type NetworkASN = {
cidr: string;
as_num: number;
as_name: string;
};

export type NetworkProxy = {
cidr: string;
proxy_type: string;
country_code: string;
country_name: string;
region_name: string;
city_name: string;
isp: string;
domain: string;
usage_type: string;
asn: number;
as: string;
last_seen: string;
threat: string;
};

export type NetworkDetails = {
location: NetworkLocation;
asn: NetworkASN;
proxy: NetworkProxy;
};

export const apiGetNetworkDetails = async (
opts: IPQuery,
abortController: AbortController
) => {
return await apiCall<NetworkDetails, IPQuery>(
`/api/network`,
'POST',
opts,
abortController
);
};

interface PermissionUpdate {
permission_level: PermissionLevel;
}
Expand Down
56 changes: 56 additions & 0 deletions frontend/src/component/NetworkInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { useState } from 'react';
import SearchIcon from '@mui/icons-material/Search';
import Typography from '@mui/material/Typography';
import Grid from '@mui/material/Unstable_Grid2';
import { Formik } from 'formik';
import { useNetworkQuery } from '../hooks/useNetworkQuery.ts';
import { LoadingPlaceholder } from './LoadingPlaceholder.tsx';
import { IPField, IPFieldProps } from './formik/IPField.tsx';
import { SubmitButton } from './modal/Buttons.tsx';

export const NetworkInfo = () => {
const [ip, setIP] = useState('');

const { data, loading } = useNetworkQuery({ ip: ip });

const onSubmit = (values: IPFieldProps) => {
setIP(values.ip);
};

return (
<Grid container spacing={2}>
<Grid xs={12}>
<Formik onSubmit={onSubmit} initialValues={{ ip: '' }}>
<Grid
container
direction="row"
alignItems="top"
justifyContent="center"
spacing={2}
>
<Grid xs>
<IPField />
</Grid>
<Grid xs={2}>
<SubmitButton
label={'Submit'}
fullWidth
disabled={loading}
startIcon={<SearchIcon />}
/>
</Grid>
</Grid>
</Formik>
</Grid>
<Grid xs={12}>
{loading ? (
<LoadingPlaceholder />
) : (
<Typography variant={'body1'}>
{JSON.stringify(data)}
</Typography>
)}
</Grid>
</Grid>
);
};
11 changes: 5 additions & 6 deletions frontend/src/component/formik/IPField.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import TextField from '@mui/material/TextField';
import { useFormikContext } from 'formik';

interface IPFieldProps {
export type IPFieldProps = {
ip: string;
}
};

export const IPField = <T,>() => {
const { values, touched, errors, handleChange } = useFormikContext<
T & IPFieldProps
>();
export const IPField = () => {
const { values, touched, errors, handleChange } =
useFormikContext<IPFieldProps>();
return (
<TextField
fullWidth
Expand Down
29 changes: 29 additions & 0 deletions frontend/src/hooks/useNetworkQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useEffect, useState } from 'react';
import { apiGetNetworkDetails, IPQuery, NetworkDetails } from '../api';
import { logErr } from '../util/errors';

export const useNetworkQuery = (opts: IPQuery) => {
const [loading, setLoading] = useState(false);
const [data, setData] = useState<NetworkDetails>();

useEffect(() => {
if (opts.ip == '') {
return;
}
const abortController = new AbortController();

setLoading(true);
apiGetNetworkDetails(opts, abortController)
.then((resp) => {
setData(resp);
})
.catch(logErr)
.finally(() => {
setLoading(false);
});

return () => abortController.abort();
}, [opts.ip]);

return { data, loading };
};
3 changes: 2 additions & 1 deletion frontend/src/page/AdminNetworkPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { FindPlayerByIP } from '../component/FindPlayerByIP.tsx';
import { FindPlayerIPs } from '../component/FindPlayerIPs.tsx';
import { NetworkBlockChecker } from '../component/NetworkBlockChecker';
import { NetworkBlockSources } from '../component/NetworkBlockSources';
import { NetworkInfo } from '../component/NetworkInfo.tsx';
import { TabPanel } from '../component/TabPanel';

export const AdminNetworkPage = () => {
Expand Down Expand Up @@ -50,7 +51,7 @@ export const AdminNetworkPage = () => {
<FindPlayerByIP />
</TabPanel>
<TabPanel value={value} index={2}>
IPInfo
<NetworkInfo />
</TabPanel>
<TabPanel value={value} index={3}>
<NetworkBlockSources />
Expand Down
11 changes: 1 addition & 10 deletions internal/ban/ban_asn_usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,7 @@ func (s banASNUsecase) Unban(ctx context.Context, asnNum string) (bool, error) {
return false, errors.Join(errDrop, domain.ErrDropASNBan)
}

asnNetworks, errGetASNRecords := s.networkUsecase.GetASNRecordsByNum(ctx, asNum)
if errGetASNRecords != nil {
if errors.Is(errGetASNRecords, domain.ErrNoResult) {
return false, errors.Join(errGetASNRecords, domain.ErrUnknownASN)
}

return false, errors.Join(errGetASNRecords, domain.ErrFetchASN)
}

s.discordUsecase.SendPayload(domain.ChannelModLog, discord.UnbanASNMessage(asNum, asnNetworks))
s.discordUsecase.SendPayload(domain.ChannelModLog, discord.UnbanASNMessage(asNum))

return true, nil
}
Expand Down
5 changes: 3 additions & 2 deletions internal/ban/ban_net_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"net"
"net/netip"
"time"

sq "github.com/Masterminds/squirrel"
Expand All @@ -25,7 +26,7 @@ func NewBanNetRepository(database database.Database) domain.BanNetRepository {
//
// Note that this function does not currently limit results returned. This may change in the future, do not
// rely on this functionality.
func (r banNetRepository) GetByAddress(ctx context.Context, ipAddr net.IP) ([]domain.BanCIDR, error) {
func (r banNetRepository) GetByAddress(ctx context.Context, ipAddr netip.Addr) ([]domain.BanCIDR, error) {
const query = `
SELECT net_id, cidr, origin, created_on, updated_on, reason, reason_text, valid_until, deleted,
note, unban_reason_text, is_enabled, target_id, source_id, appeal_state
Expand Down Expand Up @@ -124,7 +125,7 @@ func (r banNetRepository) Get(ctx context.Context, filter domain.CIDRBansQueryFi
if errCidr != nil {
ip := net.ParseIP(filter.IP)
if ip == nil {
return nil, 0, errors.Join(errCidr, domain.ErrInvalidIP)
return nil, 0, errors.Join(errCidr, domain.ErrNetworkInvalidIP)
}

addr = ip.String()
Expand Down
5 changes: 3 additions & 2 deletions internal/ban/ban_net_usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"log/slog"
"net"
"net/netip"

"github.com/leighmacdonald/gbans/internal/discord"
"github.com/leighmacdonald/gbans/internal/domain"
Expand Down Expand Up @@ -48,7 +49,7 @@ func (s *banNetUsecase) Ban(ctx context.Context, banNet *domain.BanCIDR) error {

_, realCIDR, errCIDR := net.ParseCIDR(banNet.CIDR)
if errCIDR != nil {
return errors.Join(errCIDR, domain.ErrInvalidIP)
return errors.Join(errCIDR, domain.ErrNetworkInvalidIP)
}

if errSaveBanNet := s.banRepo.Save(ctx, banNet); errSaveBanNet != nil {
Expand Down Expand Up @@ -86,7 +87,7 @@ func (s *banNetUsecase) Ban(ctx context.Context, banNet *domain.BanCIDR) error {
return nil
}

func (s *banNetUsecase) GetByAddress(ctx context.Context, ipAddr net.IP) ([]domain.BanCIDR, error) {
func (s *banNetUsecase) GetByAddress(ctx context.Context, ipAddr netip.Addr) ([]domain.BanCIDR, error) {
return s.banRepo.GetByAddress(ctx, ipAddr)
}

Expand Down
7 changes: 4 additions & 3 deletions internal/ban/ban_steam_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"context"
"errors"
"fmt"
"net"
"net/netip"
"time"

sq "github.com/Masterminds/squirrel"
Expand Down Expand Up @@ -128,8 +128,9 @@ func (r *banSteamRepository) GetByBanID(ctx context.Context, banID int64, delete
return r.getBanByColumn(ctx, "ban_id", banID, deletedOk)
}

func (r *banSteamRepository) GetByLastIP(ctx context.Context, lastIP net.IP, deletedOk bool) (domain.BannedSteamPerson, error) {
return r.getBanByColumn(ctx, "last_ip", fmt.Sprintf("::ffff:%s", lastIP.String()), deletedOk)
func (r *banSteamRepository) GetByLastIP(ctx context.Context, lastIP netip.Addr, deletedOk bool) (domain.BannedSteamPerson, error) {
// TODO check if works still
return r.getBanByColumn(ctx, "last_ip", lastIP.String(), deletedOk)
}

// Save will insert or update the ban record
Expand Down
6 changes: 3 additions & 3 deletions internal/ban/ban_steam_usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"context"
"errors"
"log/slog"
"net"
"net/netip"
"time"

"github.com/leighmacdonald/gbans/internal/discord"
Expand Down Expand Up @@ -52,7 +52,7 @@ func (s *banSteamUsecase) GetByBanID(ctx context.Context, banID int64, deletedOk
return s.banRepo.GetByBanID(ctx, banID, deletedOk)
}

func (s *banSteamUsecase) GetByLastIP(ctx context.Context, lastIP net.IP, deletedOk bool) (domain.BannedSteamPerson, error) {
func (s *banSteamUsecase) GetByLastIP(ctx context.Context, lastIP netip.Addr, deletedOk bool) (domain.BannedSteamPerson, error) {
return s.banRepo.GetByLastIP(ctx, lastIP, deletedOk)
}

Expand Down Expand Up @@ -178,7 +178,7 @@ func (s *banSteamUsecase) GetOlderThan(ctx context.Context, filter domain.QueryF

// IsOnIPWithBan checks if the address matches an existing user who is currently banned already. This
// function will always fail-open and allow players in if an error occurs.
func (s *banSteamUsecase) IsOnIPWithBan(ctx context.Context, curUser domain.PersonInfo, steamID steamid.SteamID, address net.IP) (bool, error) {
func (s *banSteamUsecase) IsOnIPWithBan(ctx context.Context, curUser domain.PersonInfo, steamID steamid.SteamID, address netip.Addr) (bool, error) {
existing, errMatch := s.GetByLastIP(ctx, address, false)
if errMatch != nil {
if errors.Is(errMatch, domain.ErrNoResult) {
Expand Down
19 changes: 10 additions & 9 deletions internal/blocklist/blocklist_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package blocklist

import (
"log/slog"
"net"
"net/http"
"net/netip"

"github.com/gin-gonic/gin"
"github.com/leighmacdonald/gbans/internal/domain"
Expand Down Expand Up @@ -253,7 +253,7 @@ func (b *blocklistHandler) onAPIDeleteBlockListWhitelist() gin.HandlerFunc {

func (b *blocklistHandler) onAPIPostBlocklistCheck() gin.HandlerFunc {
type checkReq struct {
Address string `json:"address"`
Address netip.Addr `json:"address"`
}

type checkResp struct {
Expand All @@ -267,14 +267,15 @@ func (b *blocklistHandler) onAPIPostBlocklistCheck() gin.HandlerFunc {
return
}

ipAddr := net.ParseIP(req.Address)
if ipAddr == nil {
httphelper.ResponseErr(ctx, http.StatusBadRequest, domain.ErrBadRequest)

return
}
//
//ipAddr := net.ParseIP(req.Address)
//if ipAddr == nil {
// httphelper.ResponseErr(ctx, http.StatusBadRequest, domain.ErrBadRequest)
//
// return
//}

source, isBlocked := b.nu.IsMatch(ipAddr)
source, isBlocked := b.nu.IsMatch(req.Address)

ctx.JSON(http.StatusOK, checkResp{
Blocked: isBlocked,
Expand Down
14 changes: 11 additions & 3 deletions internal/database/migrations/000081_ip4r.up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,17 @@ TRUNCATE net_location;
TRUNCATE net_proxy;

-- Replace ip_range with the ip4r type
ALTER TABLE net_asn ADD COLUMN ip_range iprange not null;
ALTER TABLE net_location ADD COLUMN ip_range iprange not null;
ALTER TABLE net_proxy ADD COLUMN ip_range iprange not null;
ALTER TABLE net_asn ADD COLUMN ip_range ip4r not null;
ALTER TABLE net_location ADD COLUMN ip_range ip4r not null;
ALTER TABLE net_proxy ADD COLUMN ip_range ip4r not null;

ALTER TABLE net_proxy DROP COLUMN ip_from;
ALTER TABLE net_proxy DROP COLUMN ip_to;
ALTER TABLE net_location DROP COLUMN ip_from;
ALTER TABLE net_location DROP COLUMN ip_to;
ALTER TABLE net_asn DROP COLUMN ip_from;
ALTER TABLE net_asn DROP COLUMN ip_to;


-- Add a temp column to map to the new type
ALTER TABLE person_connections ADD COLUMN new_ip4 ip4;
Expand Down
Loading

0 comments on commit 21742c8

Please sign in to comment.