• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2046
  • Last Modified:

IP to Decimal and Decimal to IP

Does anyone have a function that converts an IP to Decimal and a function that converts the decimal back to IP


Thanks

0
alspivey
Asked:
alspivey
  • 8
  • 7
  • 3
  • +6
1 Solution
 
mlmccCommented:
What is an IP?

mlmcc
0
 
alspiveyAuthor Commented:
Internet address i.e 192.168.0.1
0
 
ozoCommented:
perl -e "print unpack'N',pack'C*',split/\./,shift" 192.168.0.1
perl -e "print join'.',unpack'C*',pack'N',shift" 3232235521
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
cincin77Commented:
in C/C++ try inet_aton:
 inet_aton() converts the Internet host address cp from the standard numbers-and-dots notation into  binary  data  and
       stores it in the structure that inp points to. inet_aton returns nonzero if the address is valid, zero if not.


 #include <sys/socket.h>
       #include <netinet/in.h>
       #include <arpa/inet.h>
 
       int inet_aton(const char *cp, struct in_addr *inp);
0
 
WhackoCommented:
heres an ip to decimal delphi function i made some time ago. Tho i dont quite know how to reverse it :P

var
  Dec   : Array[1..4] of integer = (16777216,65536,256,1);


procedure ip2dec(ip:string; decimal: int64);
VAR ip             : Array[1..4] of Int64;
    IPCut          : string;
    Poz, i         : integer;
    total          : int64;

begin
   IPCut := ipstr;

   i := 1;
   While Pos('.', IPCut) > 0 Do
   Begin
     Poz := Pos('.', IPCut);
     ip[i] := StrToInt( Copy(IPCut,1,Poz - 1));
     Delete(IPCut, 1, Poz);
     inc(i);
   end;
   ip[4] := StrToInt(IPCut);

   Total := 0;
   i := 1;
   While i <= 4 do
   begin
     total := Total + ip[i] * dec[i];
     inc(i);
   end;
   decimal := total;
end;
0
 
mocartsCommented:
Delphi code:

type
  // since IPv4 address consists of four octets or simply dword
  TIPv4 = record
    a,b,c,d: byte;
  end;

function IPv4ToInt(const IP: string): dword;
var
  c, i, l: integer;
  ba: array [0..3] of byte;
  s: string;
begin
  c := 0;
  l := Length(IP);
  for i := 1 to l do begin
    if IP[i] <> '.' then
      s := s + IP[i];
    if (IP[i] = '.') or (i = l) then begin
      ba[c] := StrToInt(s);
      s := '';
      inc(c);
    end;
  end;
  Move(ba, Result, 4);
end;

function IntToIPv4(const IntIP: dword): string;
begin
  with TIPv4(IntIP) do
    Result := Format('%d.%d.%d.%d', [a, b, c, d]);
end;

wbr, mo.
0
 
alspiveyAuthor Commented:
Internet address i.e 192.168.0.1
0
 
mocartsCommented:
IPv4ToInt('192.168.0.1') will be 16820416.
IPv4 is in format xxx.xxx.xxx.xxx
where xxx is 8bit number (octet)

wbr, mo.
0
 
SunBowCommented:
done?
0
 
msa2003Commented:
I think, first you must specify what language you are using ;-). The following example (in Delphi) I used for my own needs:

uses
  Splitter;

type
  TIPAddress = packed record // IP-àäðåñ
    case Integer of
      1: (A4, A3, A2, A1: Byte);
      2: (A: Cardinal);
  end;

function GetIPFromString(S: String): TIPAddress;
var
  Splitter: TSplitter;
  Code, A: Integer;
  IP: TIPAddress;
label 1;
begin
  Result.A := 0;
  Splitter := TSplitter.Create(S, '.', True);
  if Splitter.Src = '' then Goto 1;
  if Splitter.Count <> 4 then Goto 1;
  if Splitter.S[0] = '*' then IP.A1 := 255 else
  begin
    Val(Splitter.S[0], A, Code);
    if (Code <> 0) or (A < 0) or (A > 255) then Goto 1;
    IP.A1 := A;
  end;
  if Splitter.S[1] = '*' then IP.A2 := 255 else
  begin
    Val(Splitter.S[1], A, Code);
    if (Code <> 0) or (A < 0) or (A > 255) then Goto 1;
    IP.A2 := A;
  end;
  if Splitter.S[2] = '*' then IP.A3 := 255 else
  begin
    Val(Splitter.S[2], A, Code);
    if (Code <> 0) or (A < 0) or (A > 255) then Goto 1;
    IP.A3 := A;
  end;
  if Splitter.S[3] = '*' then IP.A4 := 255 else
  begin
    Val(Splitter.S[3], A, Code);
    if (Code <> 0) or (A < 0) or (A > 255) then Goto 1;
    IP.A4 := A;
  end;
  Result := IP;
1:
  Splitter.Free;
end;

function GetStringFromIP(IP: TIPAddress): String;
begin
  Result := IntToStr(IP.A1) + '.' + IntToStr(IP.A2) + '.' + IntToStr(IP.A3) +
                                                          '.' + IntToStr(IP.A4);
end;

Splitter unit source may be obtainet here: http://www.serge.dsip.net/downloads/Splitter.pas

If you are using WinSock API you may prefer WinSock API native functions inet_addr and inet_ntoa (given C++ syntax):

char FAR * inet_ntoa (
  struct   in_addr in  
);

unsigned long inet_addr (
  const char   FAR *cp  
);

See Platform SDK: Windows Sockets (MSDN) for details.
0
 
WhackoCommented:
i think he should choose the SHORT solution :P
0
 
alspiveyAuthor Commented:
Hi mocarts,

Your 2 functions work great. What I'm trying to do is calculate how many ip's are contained in a range of 2 address i.e 192.168.0.8 - 192.168.1.255. And I was thinking that converting them to decimal would alow me to subtract them to get the total count. (How wrong I was)
I also was trying to step through the IP's one by one by adding 1 to the decimal and then convert it back, but that want work. Any ideas on how to do something this.

p.s msa2003 I'm using Delphi
0
 
akshayxxCommented:
u shud have specified the language of ur choice.. else everyday u'll get a solution in different programming language
0
 
mocartsCommented:
that's very simple.
example with functions provided above by me:

function CountIPs(const ipFrom, ipTo: string): int64;
var
  ipf, ipt: TIPv4;
begin
  Result := 0;
  ipf := TIPv4(IPv4ToInt(ipFrom));
  ipt := TIPv4(IPv4ToInt(ipTo));
  Result := ((ipt.a-ipf.a)*16777216) + ((ipt.b-ipf.b)*65536)
    + ((ipt.c-ipf.c)*256) + (ipt.d-ipf.d) {+ 1};
  // +1 - if you want to include ipFrom in range
end;

and function to increment by one IP:
procedure IncIPv4(var IP: TIPv4);
begin
  if IP.d < 255 then Inc(IP.d)
    else begin
      IP.d := 0;
      if IP.c < 255 then Inc(IP.c)
      else begin
        IP.c := 0;
        if IP.b < 255 then Inc(IP.b)
        else begin
          IP.b := 0;
          if IP.a < 255 then Inc(IP.a)
            else IP.a := 0;
        end;
      end;
    end;
end;

wbr, mo.
0
 
msa2003Commented:
Whacko: my solution is not big. It is universal. Because I used it to work with real sets of IP addresses.

You should use my unit the next way:

Count := Abs(GetIPFromString('192.168.0.8').A - GetIPFromString('192.168.1.255').A);

Very simple, isn't it ;-) ?

Mocart: Don't you think that there is no need to get values by multiplication? I think that the better way (which does exactly the same, but much faster) is to use packed record to set a byte of a double word ;-).

The shorter example (excluding masking and error checking) of GetIPFromString:

function GetIPFromString(S: String): TIPAddress;
var
 Splitter: TSplitter;
 Code: Integer;
begin
 Splitter := TSplitter.Create(S, '.', True);
 Val(Splitter.S[0], Result.A1, Code);
 Val(Splitter.S[1], Result.A2, Code);
 Val(Splitter.S[2], Result.A3, Code);
 Val(Splitter.S[3], Result.A4, Code);
 Splitter.Free;
end;
0
 
msa2003Commented:
And what is really better:

uses
  WinSock;

function CountIPs(const ipFrom, ipTo: String): Integer;
begin
  Result := Abs(htonl(inet_addr('1.1.1.2')) - htonl(inet_addr('1.1.1.1')));
end;

The only one line of code ;-)

Whi don't I use Int64 - because IPv4 IP address is 32-bit!

htonl and inet_addr are WinSock API functions. inet_addr gets an IP address from it's string representation in reverse byte order. htonl converts it to normal byte order.
0
 
msa2003Commented:
Sorry,

uses
 WinSock;

function CountIPs(const ipFrom, ipTo: String): Integer;
begin
  Result := Abs(htonl(inet_addr(ipFrom)) - htonl(inet_addr(ipTo)));
end;
0
 
mocartsCommented:
you are right msa2003! I have to change order of elements in my TIPv4 record.
there will be complete solution to convert to dword and back IP string.

type
 {$IFOPT R-}
   {$DEFINE RANGEOFF}
 {$ENDIF}
 EInvalidIPString = class(Exception)
 end;

 TIPv4 = record
   d,c,b,a: byte;
 end;

function IPv4ToInt(const IP: string): dword;
var
 c, i, l: integer;
 ba: array [0..3] of byte;
 s: string;
begin
 c := 3;
 l := Length(IP);
 if l = 0 then raise EInvalidIPString.Create('Zero IP string length.');
 try
 for i := 1 to l do begin
   if IP[i] <> '.' then
     s := s + IP[i];
   if (IP[i] = '.') or (i = l) then begin
     {$IFDEF RANGEOFF} {$R+} {$ENDIF}
     ba[c] := StrToInt(s);
     {$IFDEF RANGEOFF} {$R-} {$UNDEF RANGEOFF} {$ENDIF}
     s := '';
     dec(c);
   end;
 end;
 except
   raise EInvalidIPString.Create('Invalid IP string format.');
 end;
 if c <> -1 then
   raise EInvalidIPString.Create('Invalid IP string format.');
 Move(ba, Result, 4);
end;

function IntToIPv4(const IntIP: dword): string;
begin
 with TIPv4(IntIP) do
   Result := Format('%d.%d.%d.%d', [a, b, c, d]);
end;

to get count:
  Count := IPv4ToInt(sIpTo) - IPv4ToInt(sIpFrom);

to increment:
  IntToIPv4(IPv4ToInt(sIP)+1);

wbr, mo.
0
 
msa2003Commented:
Don't you think that alltrhough usage of WinSock unit (which is shipped with Delphi) is better:

To get a string from IP (now Delphi syntax):
function inet_ntoa(in: in_addr): String;

To get an IP from string:
function inet_addr(cp: string): Cardinal;

To increment the IP address:
function inc_ip(ip: string): string;
var
  addr: in_addr;
begin
  addr.S_addr := htonl(htonl(inet_addr(ip)) + 1);
  Result := inet_ntoa(addr);
end;
0
 
WhackoCommented:
no, cos if there's an old, or no winsock installed you might get errors :P also its always better to use code instead of (third party) components, because:
1. you learn more from it.
2. easier to debug cos you still know what you did.
3. users of your app wouldbt have to install extra dll's etc, just because you wanted to make an app the easy way.

if its only for personal use... just see for yourself, but i can recommend this to anyone who wants to "master" a programming language
0
 
msa2003Commented:
Yes, but i think different:
1. It is usefull to learn more about WinSock API, cos it is a native TCP/IP API
2. You still know what you did - dll's are already debugged :P
3. winsock32.dll is allwais provided with ANY 32-bit Windows system. If your system is not 32-bit, all these examples wouldn't work :P

Of course, the ways could be different. I think I provided both :-) So there is something to choose from ;-)

P. S. I could provide access to full code of my Utils unit (Splitter is just a part). This code provides extended functionality such as IP masked compare, IP sets, configuration and user management utilities etc. As a kernel it uses the functions provided ahead.
0
 
mocartsCommented:
since I use dword as result - function will work on 16, 32, 64 etc. bit systems.
of course Winsock is another way how to do it, but if you don't need Winsock why compile unit in app?
wbr, mo.
0
 
msa2003Commented:
mocarts: I noted that I had provided two different solutions. The first (with Splitter unit) doesn't use WinSock and is a part of a real billing system which is extremely stable and processes thowsands IP's every day ;-). Another solution uses functions already provided with Windows system.

Your solution will not work in 16-bit system ;-). Simoly bacause Delphi from version 2 generates ONLY 32-bit code ;-). Delphi (1) generates 16-bit code but doesn't has rather different syntax ;-).

There are the details. In the matter of fact there is not a market but a place where experts must exchange ;-).
0
 
mocartsCommented:
why did you think, code will not work on 16bit system? dword is 32bit on 16bit or on 32bit system it doesn't matter..
wbr, mo.
0
 
mocartsCommented:
0
 
msa2003Commented:
No thanx...
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

  • 8
  • 7
  • 3
  • +6
Tackle projects and never again get stuck behind a technical roadblock.
Join Now