Modify

Opened 10 years ago

Closed 9 years ago

#3012 closed defect (fixed)

dnsmasq failed to assign IP range

Reported by: uniix@… Owned by: developers
Priority: high Milestone: Kamikaze 7.09
Component: packages Version:
Keywords: dnsmasq & ipcalc.sh failure Cc:

Description

I got this error when loading dnsmasq on IXP4XX platform kernel 2.6.23.12 svn 10175

Jan 12 00:00:24 NexNet daemon.info dnsmasq[2414]: DHCP, IP range 0.0.0.100 -- 0.0.0.250, lease time 2h
Jan 12 00:00:24 NexNet daemon.info dnsmasq[2414]: DHCP, IP range 0.0.0.100 -- 0.0.0.250, lease time 12h

After some checking, actually the problem came from ipcalc.sh script which fail to detect $NETMASK & $IPADDR variable. Strange thing was, dnsmasq package & ipcalc.sh have not been changed for a month. I only happen when I upgraded to kernel 2.6.23.12 & svn 10175

Attachments (1)

ipcalc.sh (2.9 KB) - added by anonymous 10 years ago.

Download all attachments as: .zip

Change History (7)

comment:1 Changed 10 years ago by uniix@…

Problem detected to came from ipcalc.sh. It cannot handle any address that begins with "1" and it also fail to calculate netmask correctly.

root@xxxxx:/etc/rc.d# ipcalc.sh 192.168.1.1 255.255.255.0 100 50
IP=0.0.0.1
NETMASK=0.0.0.0
BROADCAST=0.0.0.255
NETWORK=0.0.0.0
PREFIX=24
START=0.0.0.100
END=0.0.0.149


root@xxxxx:/etc/rc.d# ipcalc.sh 172.16.1.1 255.255.255.0 100 50
IP=0.0.0.1
NETMASK=0.0.0.0
BROADCAST=0.0.0.255
NETWORK=0.0.0.0
PREFIX=24
START=0.0.0.100
END=0.0.0.149


root@xxxxx:/etc/rc.d# ipcalc.sh 10.1.1.1 255.255.255.0 100 50
IP=10.1.1.1
NETMASK=0.0.0.0
BROADCAST=10.1.1.255
NETWORK=10.1.1.0
PREFIX=24
START=10.1.1.100
END=10.1.1.149

comment:2 Changed 10 years ago by anonymous

The problem was caused by /usr/lib/common.awk which is called by /bin/ipcalc.sh script. What I can do is just come up with this dirty trick to fix /etc/init.d/dnsmasq to not calling ipcalc.sh script & change limit to end in webif GUI.

        leasetime="${leasetime:-12h}"
        start="$(dhcp_calc "${start:-100}")"
        limit="${limit:-150}"
#       limit="$((${limit:-150} + 1))"
#       eval "$(ipcalc.sh $ipaddr $netmask $start $limit)"
        if [ "$dynamicdhcp" = "0" ]; then END="static"; fi
        prefix=$(printf "%s.\n" "${ipaddr%.*}")
        append args "--dhcp-range=$name,${prefix}$start,${prefix}$limit,$netmask,$leasetime${options:+ $options}"
#       append args "--dhcp-range=$name,$START,$END,$NETMASK,$leasetime${options:+ $options}"

comment:3 Changed 10 years ago by Pascal

The problem lies in the transition of awk to signed integers from unsigned integers. You'll notice that the script will work for anything up to 127.255.255.255. Once the number is above 128.0.0.0 awk will choke on the integer representation of this 32-bit number and show it as negative.

The relevant documentation for awk:
http://www.gnu.org/manual/gawk/html_node/Basic-Data-Typing.html
"The advantage to integer numbers is that they represent values exactly. The disadvantage is that their range is limited. On most modern systems, this range is −2,147,483,648 to 2,147,483,647.
"Integer values come in two flavors: signed and unsigned. Signed values may be negative or positive, with the range of values just described. Unsigned values are always positive. On most modern systems, the range is from 0 to 4,294,967,295."

Currently ipcalc.sh operates by changing the IP address to an integer before applying the netmask in a sequence of and/or/lshift/rshift operations. Recommend changing this logic to operate on 8-bit sequences at a time rather than the full 32-bit IP address so as to avoid the platform/compiler/version specific issues with awk and signed integers.

comment:4 Changed 10 years ago by Pascal

To avoid the problems with 32-bit signed vs. unsigned here is a solution that uses 4-element arrays to simulate the same behavior that was seen in the old ipcalc.sh. It uses replacement functions of ipor, ipand, etc for the original "or", "and" functions in awk. Had to pass in arrays as arguments rather than the arrays by return value which didn't work. Tested on the Gateworks 2348-4 Kamikaze svn r10650 and Linksys WRT54GL Kamikaze 7.09.

ipcalc.sh:

#!/bin/sh

awk -f /usr/lib/common.awk -f - $* <<EOF
BEGIN {
	ipsplit(ARGV[1],ipaddr)
	ipsplit(ARGV[2],netmask)
	ipsplit(ARGV[3],starts)
	num=ARGV[4]
	
	ipand(ipaddr,netmask,network)
	ipcompl(netmask,complement)
	ipor(network,complement,broadcast)
	
	ipand(starts,complement,temp)
	ipor(network,temp,start)
	ipadd(network,1,limit)
	if (ipgt(limit,start) == 1) start=limit;
	
	ipadd(start,num,end)
	ipor(network,complement,temp)
	ipadd(temp,-1,limit)
	if (ipgt(end,limit) == 1) {
		ipadd(limit,0,end)
	}
	
	print "IP="ipunsplit(ipaddr)
	print "NETMASK="ipunsplit(netmask)
	print "BROADCAST="ipunsplit(broadcast)
	print "NETWORK="ipunsplit(network)
	# print "PREFIX="ipunsplit(prefix)
	
	# range calculations:
	# ipcalc <ip> <netmask> <start> <num>
	
	if (ARGC > 3) {
		print "START="ipunsplit(start)
		print "END="ipunsplit(end)
	}
}
EOF

/usr/lib/common.awk (add to bottom of file):

function ipsplit(ip,ret) {
	n=split(ip,ret,"\.")
	if (n < 4) {
		for (i=n+1;i<=n;i++)
		ret[i] = 0
	}
}

function ipunsplit(ip) {
	ret=ip[1]
	for (i=2;i<=4;i++) ret=ret"."ip[i]
	return ret
}

function ipor(ip1,ip2,ip) {
	for (i=1;i<=4;i++) ip[i]=or(ip1[i],ip2[i])
	return ip
}

function ipand(ip1,ip2,ip) {
	for (i=1;i<=4;i++) ip[i]=and(ip1[i],ip2[i])
	return
}

function ipcompl(ip1,ip) {
	for (i=1;i<=4;i++) ip[i]=255-ip1[i]
	return
}

function ipadd(ip1, number, ip) {
	ip[4] = ip1[4] + number
	carry = int(ip[4]/256)
	ip[4] = ip[4]%256
	for (i=3;i>=1;i--) {
		ip[i] = ip1[i] + carry
		carry = int(ip[i]/256)
		ip[i] = ip[i]%256
	}
	return
}

function ipgt(ip1, ip2) {
	ret=0
	for (i=1;i<=4;i++) {
		if ( ret==0 ) {
			if (ip1[i] > ip2[i]) ret=1
		}
	}
	return ret
}

Changed 10 years ago by anonymous

comment:5 Changed 10 years ago by Pascal

The attached file ipcalc.sh is an in-place replacement which fixes the problem.

comment:6 Changed 9 years ago by agb

  • Resolution set to fixed
  • Status changed from new to closed

busybox awk patched in [12427], issue resolved

Add Comment

Modify Ticket

Action
as closed .
The resolution will be deleted. Next status will be 'reopened'.
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.