Radius Service-Type [login vs framed-user]

I am just starting to experiment with radius and I’m curious how mikrotik handles the different service-types. It seems a user that should only have [Framed-User] service type is allowed to log into the router itself, using AAA from Users. Is there a way to deny users from logging into the router itself while still allowing them PPP access?

Sam

Hiya Sam,

Very much possible yes. Go through all the Check-Items listed on the MT web site… A quick example would be:

If I receive Framed-User=PPP, NAS-Port-Type=Ethernet, then I know I am authenticating a PPPoE User. If I don’t receve Nas-Port-Type, then it’s not a PPPoE Authentication request. This is obviously a quick and dirty example.

Radius is very logical. You receive a bunch of ‘Check’ items from the NAS (MT in this case), the Radius server does various checks, comparisons, etc with those Check items, and send a ‘Reply’ item back to the NAS telling it what to do with the user.

To anser your question specifically, look wider than only Service-Type. There’s a bunch of other Check items sent to the Radius server, which clearly states which PPP Service is being used, i.e. NAS-Port-Type (Which, will also not be sent if a user tried to log into the router). Therefore, if you ONLY want to allow users PPPoE Access, you implement a Check Item on Radius, stating that the authentication request MUST contain NAS-Port-Type, and the value of that attribute, MUST be ‘Ethernet’ - stated on MT’s docs as a PPPoE authentication request.

Hope it helps… Keep in mind, look at the wide picture, not only single attributes seperately. They all are important, and they all play a critical role into accomplishing various tasks.

I think I understand that part, what I can’t figure out is what differentiates a user who can PPPoE, L2TP, PPTP - versus one that can only log in with winbox or ssh (no ppp)? The request for login is below, but I only see a calling id, service-type, and nas-identifier… Is there something I am missing?

11:28:30 radius,debug new request 0d:02 code=Access-Request service=login 
11:28:30 radius,debug sending 0d:02 to 204.16.X.X:1812 
11:28:30 radius,debug,packet sending Access-Request with id 41 to 204.16.173.62:1812 
11:28:30 radius,debug,packet     Signature = 0xb1570c7eeb35ae77f1e49b57b3500c31 
11:28:30 radius,debug,packet     Service-Type = 1 
11:28:30 radius,debug,packet     User-Name = "USERID" 
11:28:30 radius,debug,packet     User-Password = 0x 
11:28:30 radius,debug,packet     Calling-Station-Id = "68.15.X.X" 
11:28:30 radius,debug,packet     NAS-Identifier = "MikroDev" 
11:28:30 radius,debug,packet     NAS-IP-Address = 204.16.XXX.XX2 
11:28:30 radius,debug resending 0d:02 
11:28:30 radius,debug,packet sending Access-Request with id 41 to 204.16.XX.XX:1812 
11:28:30 radius,debug,packet     Signature = 0xb1570c7eeb35ae77f1e49b57b3500c31 
11:28:30 radius,debug,packet     Service-Type = 1 
11:28:30 radius,debug,packet     User-Name = "USERID" 
11:28:30 radius,debug,packet     User-Password = 0x 
11:28:30 radius,debug,packet     Calling-Station-Id = "68.15.X.X" 
11:28:30 radius,debug,packet     NAS-Identifier = "MikroDev" 
11:28:30 radius,debug,packet     NAS-IP-Address = 204.16.XXX.XXX 
11:28:30 radius,debug resending 0d:02 
11:28:30 radius,debug,packet sending Access-Request with id 41 to 204.16.XX.XX:1812 
11:28:30 radius,debug,packet     Signature = 0xb1570c7eeb35ae77f1e49b57b3500c31 
11:28:30 radius,debug,packet     Service-Type = 1 
11:28:30 radius,debug,packet     User-Name = "USERID" 
11:28:30 radius,debug,packet     User-Password = 0x 
11:28:30 radius,debug,packet     Calling-Station-Id = "68.15.X.X" 
11:28:30 radius,debug,packet     NAS-Identifier = "MikroDev" 
11:28:30 radius,debug,packet     NAS-IP-Address = 204.16.X.X
11:28:30 radius,debug,packet received Access-Reject with id 41 from 204.16.X.X:1812 
11:28:30 radius,debug,packet     Signature = 0xdc6bf318175b8d72605d6b2774a72898 
11:28:30 radius,debug received reply for 0d:02 
11:28:33 radius,debug new request 0d:03 code=Access-Request service=login 
11:28:33 radius,debug sending 0d:03 to 204.16.X.X:1812 
11:28:33 radius,debug,packet sending Access-Request with id 42 to 204.16.X.X:1812 
11:28:33 radius,debug,packet     Signature = 0x057ef85fef5d302ff70ba72500bfba1d

Give http://www.mikrotik.com/docs/ros/2.9/guide/aaa_radius a GOOD read, then read it all over again.

PPPoE, NAS-Port-Type = Ethernet
aPPP, NAS-Port-Type = Async
PPTP & L2TP, NAS-Port-Type = Virtual
HotSpot, NAS-Port-Type = Ethernet

What you are seeing below, is 100% correct. Because the NAS is sending the only information that is required to distinguish between the logins.

No NAS-Port-Type, means your are NOT authenticating a PPP request. You also have no Framed-Protocol attribute, which again, is a good indication that you’re NOT authenticating PPP

Basically, the Radius Server expects certain attributes to authenticate certain groups. If a login is in group ABC, and group ABC expects to receive Service-Type=1, then users in that group will be allowed to login via SSH/FTP/etc

If you however have group XYZ expecting Framed-Protocol=PPP and NAS-Port-Type=Ethernet, then users in that group, will ONLY be allowed to connect via the HotSpot service…

If the check items in Radius, matches the check items that MT sends, Radius authenticates and send the associated Relpy items. If the check items in Radius does not match the check items received from MT, then Radius denies the authentication…

Hope it’s starting to make sense!!

In your radius users file, perhaps a example is better…

adminuser   Auth-Type := Local, User-Password == "testing", Service-Type = 1 
    Mikrotik-Group = Full

pppuser  Auth-Type := Local, User-Password == "testing", Framed-Protocol = PPP, NAS-Port-Type = Virtual
    Framed-IP-Address = 1.2.3.4

adminuser will ONLY be able to connect via SSH/FTP/Telnet, and will be authenticated to the ‘Full’ users group. pppuser, will ONLY be allowed to connect via PPPoE, and that user will be given a static IP address of 1.2.3.4

okay, im back to this and still can’t figure it out… Here are the two types of requests, one for user login and the other for ppp login:

rad_recv: Access-Request packet from host x.x.x.x:32769, id=6, length=158
        Service-Type = Framed-User
        Framed-Protocol = PPP
        NAS-Port = 709
        NAS-Port-Type = Virtual
        User-Name = "L2TP-USER"
        Calling-Station-Id = "x.x.x.x"
        MS-CHAP-Challenge = 0x.....
        MS-CHAP2-Response = 0x010022.....
        NAS-Identifier = "pip"
        NAS-IP-Address = 204.16.x.x

rad_recv: Access-Request packet from host x.x.x.x:32769, id=8, length=76
        Service-Type = Login-User
        User-Name = "WINBOXUSER"
        User-Password = "PASSWORD"
        Calling-Station-Id = "x.x.x.x"
        NAS-Identifier = "pip"
        NAS-IP-Address = 204.16.x.x

The L2TP-USER in the database only has an attribute of Service-Type=Login-User - however its allowing them to login using winbox to the router… I assumed that if the L2TP-USER didn’t have the service-type=login in their attributes it wouldn’t authenticate them ?

Sam

100% incorrect :smiley: . You’re telling it to ALLOW it to login.

Ok, show me quickly what your User Check, User Reply, Group Check, and Group Reply items are in the database for the specific group that L2TP-USER is in…

Basically, it’s a maching game. Your Radius server receives certain unique attributes for certain unique services (some of the differences, I stated in my other post above). Now, you need to tell Radius, via Group / User Check Attributes, that it must authenticate a user for a service, but ONLY IF all attributes that radius requires (the check items), matches what you want it to be.

For L2TP thus, I’d use at least the following for Check Items:

Framed-Protocol = PPP,    # Only authenticate if it's a PPP request (this immediately will deny any winbox login as a winbox login is not classified as PPP)
NAS-Port-Type = Virtual  # Only allow Port Types of 'Virtual', which is mentioned on the MT web site, and ensures we are ONLY authenticating a L2TP/PPTP User, and not for example a PPPoE user....

You use the attributes that you receive from MT to basically make a ‘access-list’. IF attribute XYZ = value, AND attribute ABC = value, AND attribute CDE = value OR (attribute blah = value AND attribute bleh = value) matches, pass a authentication, else, pass a reject

Thats it in laymans terms. But the important thing is the check attributes, you need to get them correct. I emphasize ALLOT more on Check items than Reply items on all my implementations, due to this very fact that your check items actually determine on whether or not you are going to pass authentication…

BTW Sam, I think you’re not understanding that correctly either.

Service-Type=Login means allow a ‘Shell’ login. Thus you are telling it to allow a user to log into a Mikrotik, Switch, Router, etc via something like Telnet, SSH, FTP, WinBox, etc…

From the RFC2865:

      The service types are defined as follows when used in an Access-
      Accept.  When used in an Access-Request, they MAY be considered to
      be a hint to the RADIUS server that the NAS has reason to believe
      the user would prefer the kind of service indicated, but the
      server is not required to honor the hint.

      Login               The user should be connected to a host.

      Framed              A Framed Protocol should be started for the
                          User, such as PPP or SLIP.

      Callback Login      The user should be disconnected and called
                          back, then connected to a host.

      Callback Framed     The user should be disconnected and called
                          back, then a Framed Protocol should be started
                          for the User, such as PPP or SLIP.

      Outbound            The user should be granted access to outgoing
                          devices.

      Administrative      The user should be granted access to the
                          administrative interface to the NAS from which
                          privileged commands can be executed.

      NAS Prompt          The user should be provided a command prompt
                          on the NAS from which non-privileged commands
                          can be executed.

      Authenticate Only   Only Authentication is requested, and no
                          authorization information needs to be returned
                          in the Access-Accept (typically used by proxy
                          servers rather than the NAS itself).

      Callback NAS Prompt The user should be disconnected and called
                          back, then provided a command prompt on the
                          NAS from which non-privileged commands can be
                          executed.

      Call Check          Used by the NAS in an Access-Request packet to
                          indicate that a call is being received and
                          that the RADIUS server should send back an
                          Access-Accept to answer the call, or an
                          Access-Reject to not accept the call,
                          typically based on the Called-Station-Id or
                          Calling-Station-Id attributes.  It is
                          recommended that such Access-Requests use the
                          value of Calling-Station-Id as the value of
                          the User-Name.

      Callback Administrative
                          The user should be disconnected and called
                          back, then granted access to the
                          administrative interface to the NAS from which
                          privileged commands can be executed.

For PPP, PPTP, L2TP, PPPoE, etc.. You want a Framed Service thus, NOT a Login service…

http://www.freeradius.org/rfc/attributes.html ← VERY usefull web page, and as I mentioned earlier, it is IMPERATIVE that you KNOW what each attribute means, and what the affect of it will be… Especially in Check Items as you need to know what you’re expecting the NAS to send to you.

Oops, i meant to say the L2TP-USER had service-type=framed-user, not login … typo. let me go back and finish reading the rest now : )

Sam

Yep, I think I understand how the check items need to match, which is why I am confused at why the L2TP-USER can login using ssh or winbox when they only have attribute type=framed user.

To make it more clear, here are the items in the database (mysql):


radgroupreply
id GroupName Attribute op Value
1 static Framed-Protocol := PPP
2 static Service-Type := Framed-User
3 static Framed-Compression := Van-Jacobsen-TCP-IP
4 dynamic Framed-Compression := Van-Jacobsen-TCP-IP
5 dynamic Framed-Protocol := PPP
6 dynamic Service-Type := Framed-User
7 dynamic Framed-MTU := 1460
8 mtadmin Service-Type := Login-User

radreply
id UserName Attribute op Value
1 l2tp-user Framed-IP-Address := 10.95.0.10

more to come … phone call…

Seems fine so far… As I said though, the check items are way more important than the reply items

Look at it this way… Everything the NAS (ala MT) send you, is considered CHECK items. Everything you send to the NAS, is considered REPLY items.


Excuse the funny numbers - that’s just data replication. But a quick example for a propper check/reply pair for PPPoE for example would look a little something like this (and by NO means is this standard, it’s FAR from it - it’s merely to give you an idea of the Attributes):

mysql> SELECT `UserChecks`.EntryID,
    ->        CONCAT(`User`.Username, '@', `Realm`.RealmName),
    ->        `UserChecks`.Attribute,
    ->        `UserChecks`.Value,
    ->        `UserChecks`.op
    ->   FROM `UserChecks`
    ->   LEFT JOIN `User` ON `UserChecks`.UserID=`User`.EntryID
    ->   LEFT JOIN `Group` ON `User`.GroupID=`Group`.EntryID
    ->   LEFT JOIN `GroupTimes` ON `GroupTimes`.GroupID=`Group`.EntryID
    ->   LEFT JOIN `Realm` ON `Group`.RealmID=`Realm`.EntryID
    ->   LEFT JOIN `Client` ON `Realm`.ClientID=`Client`.EntryID
    ->  WHERE `User`.isActive='y' AND
    ->        `Group`.isActive='y' AND
    ->        `Realm`.isActive='y' AND
    ->        `Client`.isActive='y' AND
    ->        `GroupTimes`.DOW=DAYOFWEEK(DATE_ADD('1970-01-01', INTERVAL UNIX_TIMESTAMP() SECOND)) AND
    ->        `GroupTimes`.StartTime < DATE_FORMAT(DATE_ADD('1970-01-01', INTERVAL UNIX_TIMESTAMP() SECOND), '%H:%i:%S') AND
    ->        `GroupTimes`.StopTime > DATE_FORMAT(DATE_ADD('1970-01-01', INTERVAL UNIX_TIMESTAMP() SECOND), '%H:%i:%S') AND
    ->        `Realm`.Realmname=LOWER(SUBSTRING('cknipe@cenergynetworks.com', (LOCATE('@', 'cknipe@cenergynetworks.com') +1))) AND
    ->        `User`.Username=LOWER(LEFT('cknipe@cenergynetworks.com', (LOCATE('@', 'cknipe@cenergynetworks.com') -1)))
    ->  GROUP BY `UserChecks`.Attribute
    ->  ORDER BY `UserChecks`.Attribute;
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    6538
Current database: UltimateRadius

+--------------------------------------+-------------------------------------------------+-----------+------------+----+
| EntryID                              | CONCAT(`User`.Username, '@', `Realm`.RealmName) | Attribute | Value      | op |
+--------------------------------------+-------------------------------------------------+-----------+------------+----+
| 6c9b56e2-833b-1029-8ba8-00005e000164 | cknipe@cenergynetworks.com                      | Password  | xxx | == |
+--------------------------------------+-------------------------------------------------+-----------+------------+----+
1 row in set (0.03 sec)

Each user obviously has their own password, therefore, a password needs to be a check item per user as we can’t really do this on a per group basis - unless you want the entire group to have the same password, which is a bit silly.

mysql> SELECT `UserReplies`.EntryID,
    ->        `UserReplies`.Attribute,
    ->        `UserReplies`.op,
    ->        `UserReplies`.Value
    ->   FROM `UserReplies`
    ->   LEFT JOIN `User` ON `UserReplies`.UserID=`User`.EntryID
    ->   LEFT JOIN `Group` ON `User`.GroupID=`Group`.EntryID
    ->   LEFT JOIN `GroupTimes` ON `GroupTimes`.GroupID=`Group`.EntryID
    ->   LEFT JOIN `Realm` ON `Group`.RealmID=`Realm`.EntryID
    ->   LEFT JOIN `Client` ON `Realm`.ClientID=`Client`.EntryID
    ->  WHERE `User`.isActive='y' AND
    ->        `Group`.isActive='y' AND
    ->        `Realm`.isActive='y' AND
    ->        `Client`.isActive='y' AND
    ->        `GroupTimes`.DOW=DAYOFWEEK(DATE_ADD('1970-01-01', INTERVAL UNIX_TIMESTAMP() SECOND)) AND
    ->        `GroupTimes`.StartTime < DATE_FORMAT(DATE_ADD('1970-01-01', INTERVAL UNIX_TIMESTAMP() SECOND), '%H:%i:%S') AND
    ->        `GroupTimes`.StopTime > DATE_FORMAT(DATE_ADD('1970-01-01', INTERVAL UNIX_TIMESTAMP() SECOND), '%H:%i:%S') AND
    ->        `Realm`.Realmname=LOWER(SUBSTRING('cknipe@cenergynetworks.com', (LOCATE('@', 'cknipe@cenergynetworks.com') +1))) AND
    ->        `User`.Username=LOWER(LEFT('cknipe@cenergynetworks.com', (LOCATE('@', 'cknipe@cenergynetworks.com') -1)))
    ->  GROUP BY `UserReplies`.Attribute
    ->  ORDER BY `UserReplies`.Attribute;
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    6540
Current database: UltimateRadius

Empty set (0.03 sec)

I send no per user reply items as such. If a user where to have a fixed IP address for example, a Framed-IP-Address as a reply item per user, would be perfect…

mysql> SELECT `GroupChecks`.EntryID,
    ->        `GroupChecks`.Attribute,
    ->        `GroupChecks`.op,
    ->        `GroupChecks`.Value
    ->   FROM `GroupChecks`
    ->   LEFT JOIN `Group` ON `GroupChecks`.GroupID=`Group`.EntryID
    ->   LEFT JOIN `GroupTimes` ON `GroupTimes`.GroupID=`Group`.EntryID
    ->   LEFT JOIN `User` ON `User`.GroupID=`Group`.EntryID
    ->   LEFT JOIN `Realm` ON `Group`.RealmID=`Realm`.EntryID
    ->   LEFT JOIN `Client` ON `Realm`.ClientID=`Client`.EntryID
    ->  WHERE `User`.isActive='y' AND
    ->        `Group`.isActive='y' AND
    ->        `Realm`.isActive='y' AND
    ->        `Client`.isActive='y' AND
    ->        `GroupTimes`.DOW=DAYOFWEEK(DATE_ADD('1970-01-01', INTERVAL UNIX_TIMESTAMP() SECOND)) AND
    ->        `GroupTimes`.StartTime < DATE_FORMAT(DATE_ADD('1970-01-01', INTERVAL UNIX_TIMESTAMP() SECOND), '%H:%i:%S') AND
    ->        `GroupTimes`.StopTime > DATE_FORMAT(DATE_ADD('1970-01-01', INTERVAL UNIX_TIMESTAMP() SECOND), '%H:%i:%S') AND
    ->        `Realm`.Realmname=LOWER(SUBSTRING('cknipe@cenergynetworks.com', (LOCATE('@', 'cknipe@cenergynetworks.com') +1))) AND
    ->        `User`.Username=LOWER(LEFT('cknipe@cenergynetworks.com', (LOCATE('@', 'cknipe@cenergynetworks.com') -1)))
    ->  GROUP BY `GroupChecks`.Attribute
    ->  ORDER BY `GroupChecks`.Attribute;
+--------------------------------------+------------------+----+-------------+
| EntryID                              | Attribute        | op | Value       |
+--------------------------------------+------------------+----+-------------+
| 7277e77a-8331-1029-8ba8-00005e000164 | Auth-Type        | := | Local       |
| 7276ec35-8331-1029-8ba8-00005e000164 | Framed-Protocol  | == | PPP         |
| 7278f993-8331-1029-8ba8-00005e000164 | NAS-Port-Type    | == | Ethernet    |
| 727b0157-8331-1029-8ba8-00005e000164 | Pool-Name        | := | IP-WLAN     |
| 727a0eba-8331-1029-8ba8-00005e000164 | Service-Type     | == | Framed-User |
| 7275f803-8331-1029-8ba8-00005e000164 | Simultaneous-Use | := | 1           |
+--------------------------------------+------------------+----+-------------+

Except for the user password, these are more than likely the most important attributes in this entire authentication process.

Auth-Type = Local, used by FreeRadius itself, for custom authentication handlers.
Framed-Protocol = PPP, I only want to authenticate PPP Users
NAS-Port-Type = Ethernet, I only want to authenticate PPPoE Users
Pool-Name = IP-WLAN, used internally by FreeRadius via rlm_ippool to allocate dynamic IP addresses
Service-Type = Framed-User, I only want to authenticate PPPs
Simultaneous-Use = 1, No duplicate connections thank you. Again, used internally by FreeRadius

mysql> SELECT `GroupReplies`.EntryID,
    ->        `GroupReplies`.Attribute,
    ->        `GroupReplies`.op,
    ->        `GroupReplies`.Value
    ->   FROM `GroupReplies`
    ->   LEFT JOIN `Group` ON `GroupReplies`.GroupID=`Group`.EntryID
    ->   LEFT JOIN `GroupTimes` ON `GroupTimes`.GroupID=`Group`.EntryID
    ->   LEFT JOIN `User` ON `User`.GroupID=`Group`.EntryID
    ->   LEFT JOIN `Realm` ON `Group`.RealmID=`Realm`.EntryID
    ->   LEFT JOIN `Client` ON `Realm`.ClientID=`Client`.EntryID
    ->  WHERE `User`.isActive='y' AND
    ->        `Group`.isActive='y' AND
    ->        `Realm`.isActive='y' AND
    ->        `Client`.isActive='y' AND
    ->        `GroupTimes`.DOW=DAYOFWEEK(DATE_ADD('1970-01-01', INTERVAL UNIX_TIMESTAMP() SECOND)) AND
    ->        `GroupTimes`.StartTime < DATE_FORMAT(DATE_ADD('1970-01-01', INTERVAL UNIX_TIMESTAMP() SECOND), '%H:%i:%S') AND
    ->        `GroupTimes`.StopTime > DATE_FORMAT(DATE_ADD('1970-01-01', INTERVAL UNIX_TIMESTAMP() SECOND), '%H:%i:%S') AND
    ->        `Realm`.Realmname=LOWER(SUBSTRING('cknipe@cenergynetworks.com', (LOCATE('@', 'cknipe@cenergynetworks.com') +1))) AND
    ->        `User`.Username=LOWER(LEFT('cknipe@cenergynetworks.com', (LOCATE('@', 'cknipe@cenergynetworks.com') -1)))
    ->  GROUP BY `GroupReplies`.Attribute
    ->  ORDER BY `GroupReplies`.Attribute;
+--------------------------------------+-------------------------+----+------------------+
| EntryID                              | Attribute               | op | Value            |
+--------------------------------------+-------------------------+----+------------------+
| e5a85344-8331-1029-8ba8-00005e000164 | Acct-Interim-Interval   | := | 3600             |
| e5a26d7c-8331-1029-8ba8-00005e000164 | Class                   | := | WLAN             |
| e5a37a9b-8331-1029-8ba8-00005e000164 | Framed-Netmask          | := | 255.255.255.255  |
| e5a4d134-8331-1029-8ba8-00005e000164 | Framed-Protocol         | := | PPP              |
| e5a60591-8331-1029-8ba8-00005e000164 | Framed-Routing          | := | Broadcast-Listen |
| e5a97448-8331-1029-8ba8-00005e000164 | MS-Primary-DNS-Server   | := | 36.0.18.198      |
| e5aa9732-8331-1029-8ba8-00005e000164 | MS-Secondary-DNS-Server | := | 4.0.18.198       |
| e5ab9178-8331-1029-8ba8-00005e000164 | Service-Type            | := | Framed-User      |
+--------------------------------------+-------------------------+----+------------------+
8 rows in set (0.02 sec)

Then here, we just have the standard bunch of attributes we sent back to the NAS, to tell the NAS how to setup the PPP Session. These will include things like rate limiting, DNS servers, Iterm Updates, basically, anything you can control in MT via Radius…

I always learn the best from example, so I hope this will make some sense to you… Once you understand this, you can really perform magic :slight_smile:

Shout if anything’s unclear… I’d be happy to have a look again for you.

thanks a billion for this - i appreciate the actual samples. I should be able to make myself understand it a little more clear.

Just out of curiousity, you have verified on your setup that ppp users can’t login using winbox ? Enable AAA radius on users and test it out. I’ll go back and see what I missed.

Sam

yup. provided you use the correct attributes, u can safely authenticate to just one service winbox/pppoe/ppptp+lt2p/dhcp/wireless/hotspot etc and deny everything else…